Search This Blog

Showing posts with label Batch File. Show all posts
Showing posts with label Batch File. Show all posts

Thursday, July 09, 2015

Logging in Powershell - transcript

I come from a strong batch file background, and so to create logs whilst running batch files was just a matter of redirecting IO to a file.

As i migrate to powershell I discovered this was not as easy, maybe I am missing something, but anyway the closest I could find was the transcript command.

By running this command it would direct any output to a file.

Start-Transcript -path $scriptPath\psOutput_name.log


Once this command is run, any output generated that would normally be directed to the powershell command window will be directed to the transcript log.

You must stop the transcript at the end of the process, otherwise you will get errors the next time it runs.
Stop-Transcript


However I found issues if the script error-ed or was terminated with out the stop-transcript command having been run.

Therefore whilst I have a transcript command in each script, the first command is always a stop-transcript command. This may throw an error if a transcript is not running, but for me that is better than having no output logged.
Start-Transcript -path $scriptPath\psOutput_name.log Stop-Transcript


Share/Bookmark

Monday, August 15, 2011

Getting round restricted Windows filenames (unc)

I recently had an issue with restricted filenames.

Normally windows will not let you create a file that has one of the restricted filenames, this is a hangover from windows past.

CON, AUX, COM1, COM2, COM3, COM4, LPT1, LPT2, LPT3, PRN, NUL

One of the systems used a UNC reference to access storage on a remote server share. By using the UNC the access allowed the system to create a file called con.xxxxx.doc, this file was in fact an uploaded user file.

The problem came when a backup process tried to access the file locally and compress and encrypt it. The process failed because of the file name.

So what to do. In the end I used the same trick that allowed the file to be created. I just referenced the file using a unc (\\servername\c$\…. etc..) rather than locally (c:\…. etc..)


Share/Bookmark

Wednesday, July 20, 2011

Installing multiple certificates on multiple remote servers

note: While doing this I had a strange issue where the certutil (running via psexec ) started complaining about arguments “Expected no more than 1 args, received x”). The command was running fine before, it just stopped working and returning this error. In the end I wiped the certutil command file (CertUtilCommands.bat) and built it from scratch, running certutil –f initially which got a dump output, then built up to the full command, doing this got the whole process working again. Its a strange one and I cannot explain it but this got it working again)

Disclaimer: While I believe all will work below, I cannot guarantee it. Please ensure you test before trying anything (which is of course what everyone does).

In my first article about installing certificates to multiple servers I used ps exec to install one certificate in pfx format.

The time arose that I had to renew this certificate, but the supplier had also changed one of their upstream server certificate so I had to install that to. So what I have done is reworked my first article and built a mechanism that allows the certutil commands to be contained in one file.

Now I wanted to attach a file to this blog post with all the necessary files, however that was not possible as blogger will not allow me to attach files… Sad smile

So below I show the folder structure, describe folder purpose and then I give the file contents for all the batch files.

Folders

image

  • pstools is available from Microsoft here
  • CertutilFiles, this folder contains the certuil files needed to be copied to the remote machine. These files should be from a Win2k3 server (see image below).

image

  • CertFiles – This is where to put the certificate files (*.crt, *.pfx) etc that you want to install.
  • reports – this is an empty folder that will contain outputs of stdout for the commands run. May help if issues encountered.

Files

serverlist.txt – a basic list of the servers you want to run the commands on. This will obviously need to be changed to your server list.

server1
server2


cc.bat – this is the primary file (run cc from the command prompt). It will prompt you for information.



ECHO OFF
:InputServerList
SET /p vserverList=Please enter filename of server list (default="serverlist.txt") :-

IF "%vserverList%"=="" (
SET vserverList=serverlist.txt
)

SET voptions=

SET /p vuser=Please enter username (default="<system account - will not have network access on remote machine>") :-

IF NOT "%vuser%" == "" (
SET voptions=-u %vuser%
) ELSE (
GOTO nouser
)

SET /p vpassword=Please enter password :-

SET voptions=%voptions% -p %vpassword%
GOTO userset

:noUser
SET voptions=-s

:userset


MD reports

FOR /F "eol=# tokens=1 delims=," %%A IN (.\%vserverList%) DO START CMD /C "startcerts.bat %%A %voptions% %vuser%>reports\output_command_%%A.txt"



startcerts.bat – This sets up a windows share on the local machine, this will allow the remote server to copy the files. The local computer IP is passed to the remote server, (IP passed only if nslookup works locally resolving the computer name to an IP), if this fails the computer name is passed. (If the computername is passed to the remote server then it will need to be resolvable at the remote server.).


The share will be removed at the end of the process.




note: I have found that psexec has issue with some antivirus software (returning all pipes busy error). If you encounter this then you should stop the antivirus software for the duration of the script. I include a net stop and net start command in the batch file, you will need to add the service name.



note:the script had issue trying to connect back to itself so I have now catered for that scenario by removing the credentials, in the psexec command, if the machine is connecting to itself.




SET Sharename=installcerts2%1
SET localserverip=

FOR /F "skip=4 tokens=2 delims=:" %%A IN ('2^>NUL nslookup %COMPUTERNAME%') DO (
SET localserverip=%%A
)

IF "%localserverip%" == "" (
SET localserverip=%COMPUTERNAME%
)

REM if localmachine name = remote machine reset options to run on local machine
IF /I "%1" == "%COMPUTERNAME%" (
SET voptions=
)

net share %Sharename%=%CD% /GRANT:everyone,READ

REM stop antivirus service, have found on win2k8 servers that this will prevent psexec from running, returning all pipes busy error.
net stop "<antivirus service>"

CALL .\PsTools\psexec \\%1 %voptions% -f -c certRemoteSetup.bat %localserverip% %Sharename%

CALL .\PsTools\psexec \\%1 -s -f -c CertUtilCommands.bat

CALL .\PsTools\psexec \\%1 %voptions% -f -c certRemoteClearUp.bat

REM stop antivirus service, have found on win2k8 servers that this will prevent psexec from running, returning all pipes busy error.
net start "<antivirus service>"

openfiles
/disconnect /A %3

net share %Sharename% \\%COMPUTERNAME% /DELETE


certRemoteSetup.bat – This copies the files in the folders certutilfiles and certfiles to the local windows temp folder (%windir%/temp). Only issue I have found here is that if the computer name of the local machine cannot be resolved from the remote server then the copy will fail as it cannot find the files to run.



xcopy /Y \\%1\%2\CertutilFiles\*.* %windir%\Temp\CertInstall\
xcopy /Y \\%1\%2\CertFiles\*.* %windir%\Temp\CertInstall\


CertUtilCommands.bat – This is the file that will need to be edited for your specific requirements.



C:
CD %windir%\Temp\CertInstall\

Certutil -f -addstore Authroot
.\<certificate1filename>.crt

Certutil -f -addstore CA
.\<certificate2filename>.crt

certutil -f -p
<password> -importpfx .\<certificate3filename>.pfx


certRemoteClearUp.bat – Delete all copied files and remove directory



DEL /Q /S %windir%\Temp\CertInstall\*.*
RD /Q /S %windir%\Temp\CertInstall

Share/Bookmark

Tuesday, April 26, 2011

Running a batch file from Service Recovery

We had an issue with a third party program that every now and again would suddenly fail. It was running as a service, now we wanted to be alerted to this so I thought I could just include a previously written batch file (slightly modified for the new purpose) in the service recovery “Run a program” section and have it alert us using email.

However I soon discovered that running a batch file from the “Run a Program” option in the service recovery tab does not work.

See here…. (This behaviour is by design…. Smile super…)

http://support.microsoft.com/kb/247929

Anyway so I thought, no worries I will use the work around forcedos…. However there is a character limit on the command, which pretty much rules this out for my purpose.

FORCEDOS: Command line too long
The command line cannot be longer than 125 characters.

So I struggled to see how I was going to get round this….

Then I thought about “scheduled tasks”… and this is how I solved the problem. The batch file is setup to run as a scheduled task with no schedule.

Then in the Service Recovery tab for the service, the program is set to

“schtasks”

and the command line parameters set to

“/RUN /TN "<taskname>"”

This now works a treat… A pain but I think a nice work around, as most of the other batch files I have are scheduled in the scheduled task manager the finished work around actually fits in quite nicely.


Share/Bookmark

Sunday, April 03, 2011

Batch File: Split Compressed Archive based on Folders not size

I have had a batch file that would use 7zip to compress and encrypt an archive. The folders that were compressed contained millions of files, and I had already moved to the 64 bit version of 7zip to get me around a previous limit. Whilst this has been working fine for months, the folders and files are continuously growing and the other day it encountered an error stating

“System error:
Not enough storage is available to process this command.”

Now this error is not related to disk space but I believe its related to server resources. I did some initial research and I found an article about IRPstack size which looks interesting as to potentially fixing this, however the archive itself was becoming unmanageable so I decided to create a split archive to create smaller archives.

Now normally you can just use the split archive functionality built into 7zip, however this works on size and creates 1 archive split into smaller files. This was not what I wanted. I wanted to split the archive based on folder structure.

C:\rootfolder

\folder1
\folder2
\folder3

I wanted to create archive for each of the folders within the rootfolder.

So I came up with a batch file that loops through the rootfolder and takes each folder and runs the archive on that folder.

Before getting into the code I have this batch called from another batch file that sets up some standard variables, like dates and program locations.

%c_DateYYYYMMDD%
%c_TimeHHMM%
"%c_7zipFolder%

@echo on
SETLOCAL ENABLEDELAYEDEXPANSION
title %c_jobName%

SET sSourceFolder=C:\rootfolder
SET sZipFilesArchiveFolder=archive\files
SET sZipFilesArchiveFileName=archivefilename

SET sRemoteServer=remoteserver1
SET sRemoteDrive=D

echo on

REM Remove the double quotes from the front and end of the root path
REM REMOVE quotes using string substiution
SET sSourceFolder=%sSourceFolder:"=%

FOR /F "DELIMS==" %%d in ('DIR "%sSourceFolder%" /AD /B') DO (

REM Set up filename for archive

SET c_ZipFilesArchive=%c_DateYYYYMMDD%_%c_TimeHHMM%_%ComputerName%_%sZipFilesArchiveFileName%_%%d_X64.7z

REM Run 7zip

"%c_7zipFolder%\7z" a -t7z -mhe=on -mhc=on -w"\\%sRemoteServer%\%sRemoteDrive%$\%sZipFilesArchiveFolder%" -p"password1" "\\%sRemoteServer%\%sRemoteDrive%$\%sZipFilesArchiveFolder%\!c_ZipFilesArchive!" "%sSourceFolder%\%%d"> “.\7zipoutput.log"

)
ENDLOCAL

So the batch file is pretty simple, but things to note are you have to use delayed expansion with the for loop to set the variable contents (hence the variable surrounded in !! and not %%, in addition the SET ENABLEDELAYEDEXPANSION at the beginning.

The script loops through the folders returned by the DIR /AD /B command, sets %%d to the folder name and that is used within the for loop to name the archive and archive the contents.

The script sets the working file for the compression to the remote location.

References

Error message: "Not enough server storage is available to process this command"

Not enough server storage


Share/Bookmark

Wednesday, June 30, 2010

Automating Installing/Importing pfx (certificate) from command line (certutil) on remote servers.

note: Please also this article

A few days ago I had to sit and install a new certificate to a number of servers. These servers did not exist in an AD environment so using group policy was not an option.

However I thought I could some how script this. I have written a few batch files in the past to execute on a remote server and to do this I used the sysinternals tool psexec. So all I needed was how to import from the command line.

I found that certutil.exe ( a free ms tool) which appears to come with windows 2003 server+ could probably some how do what I wanted. However just using the help I could not see a command to import a pfx, however after trawling Google for a while I found that there is a command but it just does not appear to be list in the certutil help (certutil /?).

So I used the following command

certutil –f –p <passwordOfPfxFile> –importpfx <filelocation>

-f : force overwrite of certificate

-p: Password of the pfx file

This command will install the certificate into the personal store of the computer account. There are additional commands to install to other stores and locations, such as “–user My” which put it into the personal store if the user, and –addstore ca. Please look up these as I only include here as a quick reference.

This command worked a treat on the local machine, so now it was just a matter of getting it to run remotely.

psexec –u <username> –p <password> \\<servername> certutil -f –p <pfxpassword> –importpfx <pfx File Location>

-u: remote server username.

-p: remote server user password.

I used the psexec command and stored the pfx file in location accessible to all servers (a unc path).

Now all I needed to was to loop through all the servers, I did this by setting up a file with all the servers listed in it. Then created two batch files one to loop through the server list and pass each server to the second batch file which contained the psexec statement above.

BatchFile1

FOR /F "tokens=1 delims= " %%G IN (.\serverlist.txt) DO batchFile2.bat %%G

This command loops through the serverlist.txt file, %%G will be the servername retrieved from the serverlist.txt file and then passed to the batchfile2.bat

BatchFile2

psexec –u <username> –p <password> \\%1 certutil -f –p <pfxpassword> –importpfx <pfx File Location>

This command takes the first parameter passed to the file (%1, the servername) and runs it via psexec on the server.

p.s

Windows2000, I found that the certutil for windows2000 moaned about the –p parameter. I got round that by copying the following files from a windows 2003 server to a temporary location on the windows 2000 servers. the call to the certutil then had to be the full path (it couldnot rely on the system path).

certreq.exe, certutil.exe, certcli.dll, certadm.dll

psexec –u <username> –p <password> \\%1 c:\templocation\certutil -f –p <pfxpassword> –importpfx <pfx File Location>


Share/Bookmark