Skip to Content

IT nieuczesane.
category

Category: DevOps/Scripting

skrypty, programy, command line i inne

powershell grep

w PS braqje czegoś aka grep. po krótkich poszukiwaniach można znaleźć polecenie ‘Select-String –pattern “czego szukam” ‘ ale po krótkich testach okazuje się, że to się zachowuje trochę niedeterministycznie… znaczy się… trzeba mieć pewność, że to, co zwraca inny cmdlet to string. wystarczy kilka doświadczeń typu:

  • get-childitem | Select-String –pattern “win” – działa ok i wypisze np. “Windows”
  • get-help | Select-String –pattern “syn” – już nie zadziała wedle oczekiwań
  • get-help get-childitem | Select-String –pattern “syn” – zadziała totalnie nie wedle oczekiwań

taki to dziwny zwierz. zaufać mu w każdym razie dość trudno w obecnej postaci. dla tego polecam przypomnieć sobie taki systemowy util, który polecam, bo działa deterministycznie:

PS C:> findstr /?
Searches for strings in files.

FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/P] [/F:file]
        [/C:string] [/G:file] [/D:dir list] [/A:color attributes] [/OFF[LINE]]
        strings [[drive:][path]filename[ ...]]

n.

Backup SVN (Windows + Apache)

Jako, że nie da się backupować bezpośrednio repozytorii SVN będących on-line, trzeba było napisać prosty skrypt, który najpierw zrobi ich hotcopy a dopiero potem backup na zadaną lokalizację sieciową. Zamiast robienia backup set i używania ntbackup można spakować cały folder docelowy i przegrać go zwykłym xcopy, w sumie wyjdzie na to samo a pewnie będzie szybciej i prościej do odzyskiwania.

Środowisko:
Windows Server 2003
Apache 2.2 z modułem SVN

' SVNbackup.vbs
' Backups all SVN repositories from selected directory + Apache config
' Author Kuba Siatkowski http://w-files.pl/author/kfaz
' ver 1.0.1


optionexplicit Const FOR_READING = 1 Dim strReposFolder, colReposFolders, strBackupFolder, colBackupFolders, strBackupLocation, strApacheLocDim objFSO,WshShell, objReposFolder, objBackupFolder, objSubFolder, objSubBackupFolder, strBackupset, fileBackupset

strReposFolder = "C:RepositorySVN"                                 ' place where all SVN repos are
strBackupFolder = "C:backup"                                      ' temp folder for local backups
strBackupLocation = "\backupserverbackupsharebackupname.bkf"     ' place for backups
strApacheLoc = “C:Apache” ‘apache directory (SVN configs, plug-ins etc)
strBackupset = strBackupFolder&“backupset.bks”


Set objFSO = CreateObject("Scripting.FileSystemObject")
Set WshShell = WScript.CreateObject("WScript.Shell")
Set objReposFolder = objFSO.GetFolder(strReposFolder)
Set colReposFolders = objReposFolder.SubFoldersSet
objBackupFolder = objFSO.GetFolder(strBackupFolder)
Set colBackupFolders = objBackupFolder.SubFoldersSet
fileBackupset = objFSO.CreateTextFile(strBackupset, True)

'delete old backups from temp folder
For Each objSubBackupFolder In colBackupFolders


objSubBackupFolder.Delete True

Next

‘hotcopy all repos from reposdir and create backupset
For Each objSubFolder In colReposFolders

WshShell.run "svnadmin.exe hotcopy "&strReposFolder&""&objSubFolder.Name&" "&strBackupFolder&objSubFolder.Name, 1, true
fileBackupset.WriteLine ""&strBackupFolder&objSubFolder.Name&""

Next

'add Apache to backupset
fileBackupset.WriteLine ""&strApacheLoc fileBackupset.close ‘do the backup
WshShell.run "ntbackup.exe backup @"&strBackupset& " /n ""SVN Repos “&Now&""" /v:yes /r:no /rs:no /hc:off /m normal /j ""SvnBackup""/l:s /f "&strBackupLocation, , true

Czy programowanie może być zabawą?

takie oto pytanie zawitało dzisiaj w moim RSS readerze, zadane przez GT – przepraszam Cię Grzesiu, że nie w komentarzach tylko tak tutaj – ale pytanie ciekawe, a odpowiedź zbyt długa, żeby ją wklepywać jako comment – a ping backa powinieneś dostać [jeśli masz włączonego]. nie traktuj tego więc jako atak – to czysta polemika (:

“A kto pamięta LOGO? Proste to było do bólu, ale uczyło myślenia.”

oj pamiętam ci ja logo, pamiętam – uczyłem się go na bosmanach 8. założeniem logo była edukacja i na początq lat 9o’  miało to sens. kilka lat temu [ok 4-5] miałem nieprzyjemność uczenia logo – takiego nowego, z innym edytorem, niby-obiektowego etc. mając porównanie czasów ‘wtedy’ oraz ‘dziś’ mogę śmiało powiedzieć – LOGO TO SYF. język nieprzemyślany, gdzie na siłę wtrącono część obiektowości, pozostawiając w wielu miejscach podejście strukturalne, totalnie zwalony edytor, który wręcz zmusza do zrobienia bałaganu w kodzie, ciężko cokolwiek znaleźć – po prostu masakra. jedyne czego można po logo oczekiwać to nauczenia się totalnie złych manier programowania, niespójności i raczej się można zrazić niż nauczyć. do dziś na murach można spotkać napisy ‘punk not dead’ a nawet czasem odbędzie się jakiś koncert – gdzie 8o% ludzi jest powyżej 4otki. z logo jest podobnie – należy pochylić czoło nad kawałkiem historii i zapomnieć.

“W systemie DOS, podobnie jak w ośmiobitowcach (nie wnikam czy było to Atari, Commodore, Spectrum czy jeszcze coś innego) proste środowisko programistyczne było dostępne od ręki. A teraz?”

a teraz od wieków w windzie jest WSH, od niedawna powershell, w linuxach bash… oj bez GUI? no to TCL … ale po co w ogóle szukać po jakiejś niszy? czemu nie Java lub .NET – pierwsze prawdziwie języki obiektowe? być może ponieważ:

“Pomijam już to, że środowiska programistyczne zazwyczaj są olbrzymimi pakietami oprogramowania, które zachowują się nieraz tak, jakby były samodzielnymi systemami.”
oraz
Pomijając kwestie środowiska, programowanie w XXI wieku nie jest tak proste jak kiedyś. Dawniej dało się napisać program mieszczący się w jednym pliku, bez tony #include i innych Using.

nie prawda. do napisania ‘hello world’ potrzebujesz dokładnie tylko samo kodu – no ok. z jednego includa trzeba dodać. i bardzo dobrze. ale jeśli chcesz coś narysować, napisać lub skorzystać np z sieci – kiedyś musiałeś napisać toooooonę kodu – teraz dołączasz bibliotekę, która i tak działa o niebo lepiej niż większość by to sama zrobiła. i jest przenośne. zamiast uczyć się ‘jak coś działa’ [np. przebijanie się przez RFC od TCP/IP] sqpiasz się na logice – w końcu developer nie musi być architektem. równie dobrze można powiedzieć, że najlepszy był assembler. po co mam pisać algorytm na rysowanie koła, skoro mogę po prostu napisać rysujOkrag(10) q:
co do kompilatora – nie trzeba instalować visual studio – może owszem, microsoft ma taką politykę, że .net kojarzy się z VS, ale przecież wystarczy dobry edytor z podkreślaniem składni [np. pspad] – zarówno do javy jak i .neta i zainstalowany framework/VM. nie jestem ‘na bieżąco’ ale są małe środowiska do obu tych języków – po szybkim googlaniu np. tutaj. małe, szybkie, do pierwszych zabaw wystarczą – wcale nie trzeba SQL ani pierdyliona dodatków.

Tylko, czy przypadkiem nie stało się tak, że zginęła w tym radość z napisania czegoś, co działa? Czy dzisiaj dziesięciolatek ma szansę siąść i napisać kilka albo kilkadziesiąt linii kodu, które zapytają o imię i wyświetlą okienko, w którym to imię zostanie wstawione w komunikat "Jasio umie programować!"?

imho – nie. co więcej – ma szansę to zrobić bez problemu, ponieważ to nie jest na tym etapie kwestia języka tylko nauczyciela oraz kompilatora. taka aplikacja to w javie tyle samo kodu w VB – a jeśli jest go więcej wizualnie, to i tak ‘sprytny edytor’ doda wszystko co potrzebne na początek – a co to oznacza można wytłumaczyć później.
różnica polega jednak na tym, że jak ktoś się zacznie uczyć języków strukturalnych, a już nie-daj-wielki-informatyku takich archaizmów jak BASIC, to potem będzie musiał się na nowo uczyć obiektowych. wiem – bo sam przez to przeszedłem i przełamanie sposobu myślenia jest dość bolesne. developerem nie zostałem [czego trochę żałuję, ale tak się potoczyło], ale miałem okazję kombinować w różnych wynalazkach – logo, basic, pascal, c, c++, java, .net, php, vbs+hta, sql, vba, fortran, c-MPI, shellowe cmd, bash itd – i po wszystkich przejściach, zakochałem się w obiektowości. dla tego z resztą tak dobrze gada mi się z AD a tak bardzo nie znoszę poronionego SQL. imho warto zainwestować czas od razu w coś, co będzie przyszłościowe, zamiast babrać się w oldschoolu. nie twierdzę, że to nie ma wartości edukacyjnych, ale to ślepa uliczka i pewne zderzenie z rzeczywistością jeśli ktoś w tym kierunq będzie podążał.

“Mówiąc w największym skrócie: Jestem za powrotem BASICa do łask!”

w-życiu-never! (;

jeśli chodzi o 1o latków – ale nie tylko – to polecam grę CeeBot – imho do osób, które chcą efekty zobaczyć najszybciej – docieranie poprzez fabułę jest najefektywniejszy – i nie tylko zobaczymy ‘jaś jest programistą’ ale w ciągu kilq chwil można sterować własnym robotem! Chciałem nawet robić z tego zajęcia, ale licencja edu była za droga na moją kieszeń, a uczelnia nie chciała wydawać ):

n.

Przenoszenie nieaktywnych kont do innego OU

Trzeba było znaleźć wszystkich użytkowników, którzy nie logowali się od dłuższego czasu i przenieść ich do innego OU.
Problemy jakie się pojawiły to wartość atrybutu LastLogonTimeStamp, która jest specyficzna (liczba milisekund od epoki) i przenoszenie obiektów w AD. O ile pierwsze było proste do wygooglania o tyle z drugim strasznie ludzie kombinują, piszą miliony linii kodu i generalnie żadne z tych rozwiązań mi się nie podobało. Chwila samodzielnego kombinowania, trochę rzeźby i olśnienie w postaci, że PowerShell to przecież… shell :) i że działają w nim komendy commandlinowe takie jak np. dsmove :)

Poniżej skrypt, który znajduje wszystkich w danym OU , którzy nie logowali się od 14 miesięcy i przenosi ich od OU inactive. Minimalne wymagania: domena w trybie “Windows Server 2003”

Ustawianie msSFU30GidNumber dla wszystkich grup w domenie

Linuxy potrzebują parametru msSFU30GidNumber żeby widziały grupy z Active Directory. Do tej pory pojedyńcze MsSFUGidy robiliśmy ręcznie z ADSIEdit, jednak kiedy przyszło ponad sto nowych grup to trzeba było to jakoś oskryptować.

Skrypt poniżej:

  1. znajduje maksymalny MsSFUGid w domenie
  2. wszystkim grupom, które nie mają msSFUGID przypisuje kolejne numery 

Jego wadą jest to, że dodaje Gidy wszystkim grupom ale to można zmienić np. poprzez ustawienie odpowiedniego roota przed drugą pętla.

$Root = New-Object DirectoryServices.DirectoryEntry $strROOT
$Searcher = New-Object DirectoryServices.DirectorySearcher
$Searcher.SearchRoot = $root
$searcher.Filter =  "(&(objectClass=Group))";
$numer = 0;
$gid ;
$groups = $searcher.findAll();
foreach ($group in $groups)
{
   $de = New-Object DirectoryServices.DirectoryEntry $group.Path;
   $gid = [int]$de.msSFU30GidNumber.ToString();
#  write-host $gid ";" -NoNewLine;
#  write-host $de.name;
   if ($numer -lt $gid )
   {
     $numer = $gid;
#    $numer;
   }
}
$numer++;

foreach ($group in $groups)
{
  $de = New-Object DirectoryServices.DirectoryEntry $group.Path;
  $gid = [int]$de.msSFU30GidNumber.ToString();
  if ($gid -eq 0)
  {
    $de.msSFU30GidNumber = $numer;
    $de.SetInfo();
    write-host $numer ";" -NoNewLine;
    write-host $de.name;
    $numer++;
  }
}

Pozwalanie użytkownikom na uruchamianie/zatrzymywanie serwisów

Mamy na stacji zainstalowanego Apacha, Network Inspectora czy Flash Server i nie chcemy żeby chodziły one przez cały czas i bezsensownie zżerały nam zasoby. Chcemy pozwolić użytkownikowi na uruchamianie/zatrzymywanie serwisów i nie nadawać mu zbędnych uprawnień. Najprościej jest to zrobić ustawiając z poziomu domeny odpowiednią polisę która ustawi odpowiednie ACL na dany serwis (tak serwisy też mają ACL :o ).
Co jednak zrobić w momencie gdy komputer nie jest w domenie? Zawsze wydawało mi się, że wszystko da się ustawić w Local Security Policy. Windows + R wpisuję secpol.msc (albo gpedit.msc, jak kto woli ;) ) enter i nie ma serwisów :-o . Wszystko wskazuje na to, że nie da rady tego ustawić lokalnie jednak z pomocą przychodzi Security Configuraration and Analysis (dla nieświadomych start -> run -> mmc -> ctrl+m -> add -> Security Configuraration and Analysis ). Dodaję nową bazę, importuję template (dla bezpieczeństwa polecam setup security.inf), analizuję komputer, po czym kiedy już pokaże mi się drzewko wchodzę w System Services wybieram interesujący mnie serwis i ustawiam mu ACL’ki :) .
Ciekawe czemu jest to wycięte z interfejsu w secpol.msc? Po co wycieli coś co i tak da się ustawić? bez sensu…

Po tem jeszcze warto dać użytkownikom narzędzie pozwalające na wygodnie uruchamianie/zatrzymywanie serwisów. Może to być prosty batch wyglądający mniej więcej tak:
NET START "Nazwa serwisu"
albo tak:
NET STOP "Nazwa serwisu"

A gdybyśmy chcieli pisać to w Visual Basicu (np. po to żeby sprawdzać coś zanim nasz serwis wstanie, zrobić ładny interface graficzny itp. itd.) to przyda się ten kawałek kodu:

' Uruchom zatrzymaj serwis
option explicit
dim queryString
dim Service, ServiceSet

queryString = "select * from Win32_Service where Name=’Nazwa serwisu’ and State=’Stopped’"
Set ServiceSet = GetObject("winmgmts://.").ExecQuery(queryString)

if ServiceSet.Count <> 0 then
WScript.echo “Uruchamiam serwis”
for each Service in ServiceSet
Service.StartService()
next
else
WScript.echo “Jesteś kretynem, serwis już działa”
end if

Jakie aliasy stworzyć w shellu?

Poniższe pokazuje listę poleceń wraz z ich ilością wywolanych np. w bash albo ksh.

Jeśli jakieś rozbudowane polecenie wywołujesz często, może warto zrobić aliasa dla niego:

history|awk '{print $2}'|awk 'BEGIN {FS="|"} {print $1}'|sort|uniq -c|sort

MUI – script it

Ostatnio siedzę i bawię się windowsowym Multilingual User Interface. Posiłkując się tym oto artykułem zintegrowałem MUI z instalką na RISie. Ale tu pojawił się problem – jak niezbyt technicznym ludziom pokazać sposób zmiany języka? Tutorial? Nieeeeeee. Za dużo pracy ;) Idąc za radą NeXoRa „If it moves – script it” udało mi się z Kfaz’a pomocą spłodzić coś takiego:

Piczek.vbs

jap.reg

Ogólnie idea jest prosta. Podmień wpisy w rejestrze (znalezienie ich trwa krótką chwilę), zabij explorera i uruchom go w kontekście nowego UI. Co do kodów języków, to są one dostępne tutaj.

dla programistów

siedzę nad c# zdobywając tytuł ‚master of strings’ bo muszę pisać coś w stylu dziwnego parsera. nauczyłem się regexpów, i dziwnych wynalzków do konwertowania.

i tak a propos stringów

tutaj jest jeszcze kilka fajnych od bartosza:
http://stackoverflow.com/questions/84556/whats-your-favorite-programmer-cartoon

a teraz mała dziwnostka:
oczywiście dotarłem do kłamstwa, nad którym musiałem się sporo nabiedzić. funkcji konwertujących jest w pytkę ale oczywiście jak się ma konkretny pomysł to nic nie działa jak powinno. ot taki świetny link pokazujący potęgę konwersji. jest tam taki opisik:

Every object has a method called ToString that returns a string representation of the object. The ToString method can accept a string parameter, which tells the object how to format itself – in the String.Format call, the formatting string is passed after the position, for example, “{0:##}”


no i qpa. problem: skonwertować liczbę zmiennoprzecinkową tak, aby była wyrównana do prawej, z dokładnością do dwóch znaków po przecinq w zapisie amerykańskim [‚.’ oddziela część dziesiętną]. no więc można byłoby tak:

float flt=-1234,289F;
string out= flt.ToString("{0,15:0.00}");

co oczywiście nie zadziałało. taka konwersja działa w ogóle bardzo dziwnie – wszystkie znaczki { , : etc – traktowane są jak część liczby i wychodzi z tego:

-{1 2315:4,29}

a więc trochę jakby nie to. ponieważ występuje w zdaniu ‚formatuje sam siebię’ a więc można pominąć {0} bo wiadomo, że to o niego chodzi. Ciekawie traktowany jest minus – zupełnie jakby liczba składała się z liczby i z minusa:

string out=flt.ToString(" 0.00");

co powinno pokazać liczbę przesuniętą o klika spacji w prawo. wynik:

- 1234,29

wygląda na to, że ToString z przeciążenia na liczbie nie przyjmuje parametrów formatowania. finalnie trzeba było skomplikować:

string out=string.Format("{0,15}",flt.ToString("0.00",new System.Globalization.ClutureInfo("en-US")));

ufff.. niuanse językowe…

shutdown zdalnego kompa

niby nic skomplikowanego i jest masa różnych tooli do tego celu. podstawowym ograniczeniem w większości jakie testowałem był brak możliwości podania user/pass. czyżby było to niemożliwe? eeee tam… oczywiście, że się da. Oto skrypcik, który pokazuje jak stworzyć moniker WMI tak, aby podać odpowiednie credsy i wykonać restart:

CONST SH_LOGOFF = 0
CONST SH_FLOGOFF = 4
CONST SH_SHUTDOWN = 1
CONST SH_FSHUTDOWN= 5
CONST SH_REBOOT = 2
CONST SH_FREBOOT = 6
CONST SH_POWEROFF = 8
CONST SH_FPOWEROFF=12

strComputer = "192.168.1.123"

'tak to sie robi normalnie:
'Set OpSysSet = GetObject("winmgmts:{impersonationLevel=impersonate,(Shutdown)}//"&strComputer&"/root/cimv2")

'a tak jest to samo, podajac credsy:
set objLocator = CreateObject("WbemScripting.SWbemLocator")
set objWMI = objLocator.ConnectServer(strComputer, "rootcimv2", "nexor", "PASSWORD")
objWMI.Security_.ImpersonationLevel = 3
objWMI.Security_.Privileges.AddAsString "SeShutdownPrivilege", True

Set colOperatingSystems = objWMI.ExecQuery("SELECT * FROM " & "Win32_OperatingSystem WHERE Primary = true")

For Each objOperatingSystem in colOperatingSystems
ObjOperatingSystem.Win32Shutdown(SH_FSHUTDOWN)
Next

jak widać cały myk jest w zamianie standardowego monikera na złożony, poprzez utworzenie obiektu SWbemLocator a potem.. no właśnie – zalezienie sposobu na definicje obiektu security i specjalnych uprawnień – wypisane w skrypcie „seShutdownPrivilege” wyszperałem w necie bo te natechnecie są jakby na odwrót – metoda AddAsString przyjmuje najwyrazniej wartości opisane w kolumnie ‚descritpion’ a nie ‚Wbemdisp.tlb Constant’ co wydawałoby się logiczniejsze.