Thursday, August 27, 2009

I jak tutaj przetestować uaktualnienie.

Ehh, jak to zwykle bywa przymierzyłem się do instalacji SP2 na jednej z produkcyjnych maszyn. Na początku testy na maszynach wirtualnych z podobnymi usługami. Wszystko przechodzi bez problemu. Skoro udało się na jednej, przeszło też na drugiej to kolej na uaktualnienie jednego z serwerów produkcyjnych. Aby nie powodować przestojów wstałem sobie wcześnie i na 7.00 byłem już w pracy. Szybkie odpalenie instalacji i zrobienie kawy. Dobiega 8.00 Instalator SP2 zamyka system. Ponowne uruchomienie Stage 1 –20 minut, Stage 2 – 30 minut, Stage 3 –40 minut. Dobiega 9.30 – trochę nerwowa sytuacja, powoli dzwonią telefony. Nagle Stage 3 of 3 100% Complete. Człowiek zadowolony zasiada przy konsoli by sprawdzić czy wszystko działa poprawnie a tutaj nagle komunikat: Service Pack didn’t install. Reverting changes ??:/ Godzina 11 cofanie zmian trwa i ciekawe czy się dziś skończy. Na szczęście system podniósł odpowiednie usługi i telefony ucichły. Teraz przypominają mi się komunikaty jak aktualizowałem sobie Linuxa, masa przewijającego się tekstu. Zawsze zastanawiałem się dlaczego nie zrobią paska postępu i nie wrzucą komunikatów w jakieś ukryte okno. Teraz chciałbym zobaczyć, zamiast “ Service Pack didn’t install. Reverting changes.”, przewijające sie tony tekstu, które jasno wskazywały, że instalator nadal pracuje a nie tylko rusza ładnym kółkiem:(

Wednesday, August 26, 2009

Pobieranie nazwy hosta z dhcp.

Jakiś tydzień temu zabrałem się za kończenie nowych obrazów dla komputerów na salach laboratoryjnych. Poza drobnymi zmianami (dystrybucja lekkich aplikacji via SCCM) chciałem zminimalizować czas jaki poświęcałem na zmianę nazw komputerów po klonowaniu. Kilka lat temu przyjęliśmy, że komputery na salach będą się nazywać KompXXX-YY. Gdzie XXX to numer sali a YY to komputer na miejscu YY licząc od prawej strony sali. W systemach Linux rozwiązanie było proste :) Dorzuciliśmy opcję 12 do DHCP i systemy pobierały sobie odpowiednią nazwę z serwera DHCP. W przypadku Windows sprawa się komplikuje i dobrze by było nazwy zmienić na samym początku by nie robić sobie bałaganu. Nazwę można pobrać czy wygenerować na kilka sposobów:

  • pobranie nazwy z DNS – wszystko fajnie, tylko jak nazwy nie mam w DNS bo pojawi się po dodaniu Windowsa do domeny
  • wykorzystanie Sysprepa do generowania nazwy Komp400-XX – Muszę mieć kilka plików unattend do Sysprepa :/
  • przeparsowanie otrzymanego Adresu IP i wygenerowanie nazwy komputera.  - Czasem od naszej reguły nazewnictwa zdarzają się wyjątki:)
  • pobranie nazwy z DHCP – idealne rozwiązanie.

 

Skoro miałem wszystkie nazwy w DHCP to teraz wystarczyło pobrać odpowiednią opcje i zamienić nazwę stanowiska:) Jak sie okazało otrzymanie nazwy komputera z DHCP i wrzucenie jej do jakieś zmiennej nie jest takie proste. Jedyne dostępne API dla Windowsowego klienta DHCP jest napisane w C++:/  Opcje z DHCP pobieramy za pomocą funkcji DHCPRequestParams, która przyjmuje na wejściu kilka parametrów. Między innymi wymagane jest podanie nazwy interfejsu sieciowego. TUTAJ UWAGA nazwa interfejsu jest rozumiana jako identyfikator urządzenia a nie jako np. “Połączenie lokalne”. Identyfikator również możemy sobie wyciągnąć za pomocą API do interfejsów sieciowych.  Przyznam się, że stworzenie działającej aplikacji, która pobiera identyfikator pierwszego interfejsu a następnie wyciąga z DHCP odpowiednią nazwę zepsuł mi trochę krwi. Najpierw musiałem sobie przypomnieć pewne podstawy Visual C++, potem musiałem załapać, że w nazwie interfejsu mam podać identyfikator. Następnie musiałem rozgryźć jak dynamicznie wyszukać ten identyfikator. Koniec końców udało mi się napisać mały programik w VC++, który pobiera odpowiednią opcje z DHCP i za pomocą newsida zmienia nazwę i SID. Poniżej kod, który pobiera id pierwszego interfejsu i następnie wyciąga z DHCP nazwę stacji.  Przypominam iż z zawodu nie jestem programistą i na samym początku dążę do tego by kod działał wedle moich oczekiwaniami. Następnie jak mam czas to staram się go upiększać. W kodzie częściowo starałem się wykorzystać przykłady dostępne na stronach MSDN.

#include < winsock2.h>
#include < iphlpapi.h >
#include < stdio.h >
#include < stdlib.h >
#include < windows.h >
#include < dhcpcsdk.h >
#include < string >
#include < wchar.h >
#pragma comment( lib, "dhcpcsvc.lib" )
#pragma comment(lib, "IPHLPAPI.lib")
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

int __cdecl main()
{
CONST int iAdapterIDLenght= 260;
CONST int iHostnameLenght=60;
int dw;
CHAR pszHostNameBuf[iHostnameLenght];
DWORD dwError, dwSize;
CHAR TmpBuffer[iHostnameLenght];
WCHAR wcAdapterName[iAdapterIDLenght];
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);

pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(sizeof (IP_ADAPTER_INFO));
if (pAdapterInfo == NULL)
{
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return 1;
}
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
{
FREE(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(ulOutBufLen);
if (pAdapterInfo == NULL)
{
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return 1;
}
}

if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR)
{
pAdapter = pAdapterInfo;
dw = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pAdapter->AdapterName, -1, wcAdapterName, 0);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pAdapter->AdapterName, -1, wcAdapterName, dw);

DHCPCAPI_PARAMS DhcpApiHostNameParams = {
0, // Flags
OPTION_HOST_NAME, // OptionId
FALSE, // vendor specific?
NULL, // data filled in on return
0 // nBytes
};
DHCPCAPI_PARAMS_ARRAY RequestParams = {
1, // only one option to request
&DhcpApiHostNameParams
};

DHCPCAPI_PARAMS_ARRAY SendParams = {0,NULL};

dwSize = sizeof(TmpBuffer);
dwError = DhcpRequestParams(
DHCPCAPI_REQUEST_SYNCHRONOUS, // Flags
NULL, // Reserved
wcAdapterName, // Adapter Name
NULL, // not using class id
SendParams, // sent parameters
RequestParams, // requesting params
(PBYTE) TmpBuffer, // buffer
&dwSize, // buffer size
NULL // Request ID
);

if( ERROR_MORE_DATA == dwError )
{
printf("Error: %s",dwError);
}

if( NO_ERROR == dwError )
{

if( DhcpApiHostNameParams.nBytesData )
{

CopyMemory(pszHostNameBuf, DhcpApiHostNameParams.Data,DhcpApiHostNameParams.nBytesData);
pszHostNameBuf[DhcpApiHostNameParams.nBytesData] = '\0';
printf("(12) DHCP Host Name: %s\n",pszHostNameBuf);
return 0;
}
}
else
{
printf("Error: %u",dwError);
}

}
else
{
printf("GetAdaptersInfo failed with error: %d\n", dwRetVal);

}
if (pAdapterInfo)
FREE(pAdapterInfo);
getchar();
return 0;
}


W wolnej chwili postaram się napisać małą bibliotekę do podpięcia pod C#, tak bym mógł pobrać dowolne opcje z DHCP.