Startup script to generate uninstall command - windows

I have a text file of the format:
computername1 uninstallkey1
computername2 uninstallkey2
...
computername200 uninstallkey200
I am trying to write a startup script (batch file or powershell?) that generates a msiexec command that looks up and implants the correct key for each computer it executes on e.g.:
msiexec /x install.msi key=uninstallkey
If I have not made anything clear, please ask and any help is much appreciated!

#ECHO OFF
SETLOCAL
FOR /f "tokens=1*" %%i IN (yourtextfilename.txt) DO (
IF /i %%i==%COMPUTERNAME% ECHO MSIEXEC /x install.msi key=%%j
)
This should do as you require - yourtextfilename.txt contains the data, presumably on a shared drive; finds the line where the computername in column 1 is the same as the computername returned by %computername% in the target computer's environment.
(all case-insensitive EXCEPT %%i and %%j which must match and be the same case)
Command simply ECHOed - remove the ECHO keyword after verification to activate.

In PowerShell,
$comp = Import-CSV -Delimiter " " -Path C:\comp.txt -Header computername,uninstallkey
$comp | ForEach-Object {
if ($env:COMPUTERNAME -eq $_.Computername) {
Start-Process -FilePath "msiexec.exe" -ArgumentList "/x install.msi key=$_.uninstallkey"
}
}

Related

Change Windows settings with coding

I would like to have a code, that would check current Windows settings for which decimal symbol is currently used, "comma" or "dot". If it is "comma", the code should change it to the "dot" and if it was "dot" - to "comma".
I would like to have this code as a shortcut on the desktop or so, and that it would be run by simply doubleklicking on it.
Is there anyone who might help me with that? In my understanding it should be rather easy, but I don't have experience in these tasks, yet.
Thanks!!
You can do that in a couple of ways, but I'm guessing you're looking for a reatively easy way of doing it.
Powershell
With Powershell, you can get the current value of the decimal notation by using this:
(Get-ItemProperty -Path "HKCU:\Control Panel\International" -Name sDecimal).sDecimal
And since you're about to change it to something else, you would also need to handle the thousands grouping symbol. Following the above logic, you would do
(Get-ItemProperty -Path "HKCU:\Control Panel\International" -Name sThousand).sThousand
Both of these get the settings for the current user, and changing them would be a change for that user. If you're comfortable with that, you would do the following.
First, open any text editor (Notepad would do, as well), and then paste the following code.
$currentDecimal = (Get-ItemProperty -Path "HKCU:\Control Panel\International" -Name sDecimal).sDecimal # let's get the current decimal separator
# if the current decimal is equal to a dot
if($currentDecimal -eq ".") {
Set-ItemProperty -Path "HKCU:\Control Panel\International" -Name sDecimal -Value ","
Set-ItemProperty -Path "HKCU:\Control Panel\International" -Name sThousand -Value "." # this line will always change the thousands grouping symbol. If you don't want that, omit this line
$wasDecimalChanged = $true
} elseif($currentDecimal -eq ",") {
Set-ItemProperty -Path "HKCU:\Control Panel\International" -Name sDecimal -Value "."
Set-ItemProperty -Path "HKCU:\Control Panel\International" -Name sThousand -Value "," # same as in the first if, omit this, if you don't want to change the thousands grouping symbol
$wasDecimalChanged = $true
} else {
$wasDecimalChanged = $false
}
if($wasDecimalChanged) {
write-host("Decimal symbol was changed to " + (Get-ItemProperty -Path "HKCU:\Control Panel\International" -Name sDecimal).sDecimal)
}
exit
You would then save this as a *.ps1 file.
This script may require running with elevated (administrator) privileges. Also, the system you'll be running this script on may require enabling of running Powershell scripts. You can do that in a couple of ways:
by changing the registry on that particular system, like this. This will also let you run your script by double clicking on it
by manually enabling the running of Powershell scripts, by starting Powershell as an administrator, and running this command: set-executionpolicy remotesigned. After doing that, you would place a script in a directory anywhere in the system. Then you would create a shortcut, and place it on the Desktop / any other location, and by double-clicking, run your script
Please bear in mind that both of these will open up the system in question to possibile exploits and runnings of malicious scripts.
Batch script
If you want to do it through a batch script, it would look something like this.
First, let's see how we can retrieve the current value for the decimal separator.
reg query "HKEY_CURRENT_USER\Control Panel\International" /v sDecimal
This part
reg query "HKEY_CURRENT_USER\Control Panel\International"
let's us know all the keys within that specific registry entry, and that's alright, but we only need the one for the decimal separator. By adding this
/v sDecimal
our command becomes
reg query "HKEY_CURRENT_USER\Control Panel\International" /v sDecimal
and we get what we want. Well, sort of, since the response to our command is:
HKEY_CURRENT_USER\Control Panel\International
sDecimal REG_SZ .
The only thing we need from that response is the last character - the dot (in this case, it might've been a comma). So, to extract the separator, we would need to do something like this (from within the script - running this in command prompt would require some changes).
for /F "tokens=3" %%A in ('reg query "HKEY_CURRENT_USER\Control Panel\International" /v sDecimal') DO (Echo %%A)
This would return just the decimal separator.
The rest of the logic is more or less the same as in the Powershell example, the only thing that differs is the syntax. Putting it all together, we get
#echo off
title "Decimal change"
REM let's get our current decimal symbol, and give its value to a variable
for /F "tokens=3" %%A in ('reg query "HKEY_CURRENT_USER\Control Panel\International" /v sDecimal') DO (SET currentDecimal=%%A)
IF /i "%currentDecimal%"=="," goto changeComma
IF /i "%currentDecimal%"=="." goto changeDecimal
echo Symbol is not a decimal point or a dot! I've changed nothing!
goto commonexit
:changeComma
%SystemRoot%\System32\reg.exe add "HKEY_CURRENT_USER\Control Panel\International" /v sDecimal /t REG_SZ /d "." /f
%SystemRoot%\System32\reg.exe add "HKEY_CURRENT_USER\Control Panel\International" /v sThousand /t REG_SZ /d "," /f
goto commonexit
:changeDecimal
%SystemRoot%\System32\reg.exe add "HKEY_CURRENT_USER\Control Panel\International" /v sDecimal /t REG_SZ /d "," /f
%SystemRoot%\System32\reg.exe add "HKEY_CURRENT_USER\Control Panel\International" /v sThousand /t REG_SZ /d "." /f
goto commonexit
:commonexit
exit
The REG_SZ bit is used because this is the way the value is stored in the registry - if you were to open the Registry editor on your Windows machine, and then navigate to
Computer\HKEY_CURRENT_USER\Control Panel\International
you would see a list of various settings, and all of them would be of the type REG_SZ .
As with the Powershell script, you would c/p this into a Notepad file. Unlike the Powershell script, you would save this one with a *.bat extension.
The notes regarding elevated / admin privileges, and placing a shortcut on the Desktop apply as well.

How to pass variable from Batch File to a Powershell Script

I have a batch file that copies user files from one computer to another networked computer.
#echo off
cls
#echo Type the old Computer Name
set /p asset=
REM robocopy.exe \\%asset%\c$\ C:\ /S /Z /XJD /XJ /XA:SH /XA:T /XD "Dir1" "Dir2" /XF *.dll *.log *.txt *.exe /log+:"\\server\path\%asset%-to-%computername%-Transfer.log" /NP /FP /V /TEE
PowerShell.exe -Command "& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -Verb RunAs}"
pause
This is my PowerShell script:
$source = "\\${env:asset}\C$\Temp\Source"
$dest = "C:\Temp\Dest"
Write-Output $source
Read-Host "Press ENTER to quit"
I then need to call a PowerShell script that invokes an admin login, then pass the %asset% and %useraiu% variables.
I can't seem to figure out how to pass the %asset% and %useraiu% from my batch file to the PowerShell script.
I have found that if you are calling the Powershell script from a batch file and need to have the Powershell script run with admin, you would need to use this syntax.
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File """"%~dpn0.ps1"""" """"%asset%"""" ' -Verb RunAs}"
The PowerShell script name and parameters need to be wrapped in 4 double quotes in order to properly handle paths/values with spaces
This is the only solution that worked for me so far.

Bat script to retrieve folder size (windows)

I need to write a script .bat that give me the free space of a certain disk and the detail of all folders with the relative dimension and write it in a simple text file (just to check the distribution of used space).
Thanks a lot in advance!
dir /a /s | findstr /b /c:" " > file.txt
The FileSystemObject can do this for you. It is accessible from PowerShell (among other sources).
PowerShell -NoProfile -Command "$fso = New-Object -COMObject Scripting.FileSystemObject; Get-ChildItem YOUR_ROOT_DIRECTORY -Recurse -Directory | %% { $f = $fso.GetFolder($_.FullName); '{0},{1}' -f $f.Size,$_.FullName };"

Not able to capture output by runas command

I have to automate test cases.
Tasks:-
Step:-Open administrative command prompt from powershell.
Step:-Execute a batch file on the administrative command prompt.
Step:-Batch file includes some set of commands, including a execution of an exe.
For Example:- runas /user:administrator /savecred someCmd.exe >>D:\output.txt
Step:-Capture output of the exe in a variable for verification of the output.
i have used "
start-process -verb runas cmd.exe $param" cmdlet for opening administrative command prompt(Step 1).
Where $param contains the batch file to be executed.
Problem Statement:- When batch file executes the runas command mentioned above, it opens a new command prompt and the output is displayed in the prompt and it closes itself.
i am not able to capture the output(not getting written in the output.txt) based on which i have to do some verification.
you can use the the output redirection from the batch :
$params="/C ipconfig /all 2>&1 >>c:\temp\test.txt"
start-process -verb runas cmd.exe $params
gc c:\temp\test.txt
I ended up creating a wrapper batch file OutputWrapper.bat that takes at least two arguments:
1) output file
2) command
3) [optional] arguments
#ECHO OFF
IF "%2" == "" GOTO usage
SET OUTPUTFILE=%1
SET COMMAND=%2
SET ARGS=
SHIFT /2
:loop1
IF "%2"=="" GOTO exec
SET ARGS=%ARGS% %2
SHIFT
GOTO loop1
:exec
ECHO Command [%COMMAND%]
ECHO Arguments [%ARGS%]
ECHO Output file [%OUTPUTFILE%]
%COMMAND%%ARGS% > %OUTPUTFILE% 2>&1
GOTO end
:usage
ECHO Usage: %~nx0 outputfile command [arguments]
:end
and calling it from PowerShell like this:
$outFile = "C:\Temp\Deploy.out";
Start-Process -FilePath .\OutputWrapper.bat -ArgumentList "$outfile","whoami.exe","/priv" -Verb RunAs -Wait
Get-Content $outFile;
Solution
Open administrative command prompt from powershell.
executed a batch file in the runas command. For example: runas /user:administrator /savecred mybatch.bat
Batch file includes some set of commands, including a execution of an exe. For example someCmd.exe >>D:\output.txt
Capture output of the exe in a variable for verification of the output.
Now the output was captured and was written into a file. My target was to capture the output of the command and this was the solution through which I solved it.
I had the same problem and solved it by the use of gsudo. It let me run the elevated command and tunneled the output back from it.
gsudo {command-to-execute}
Improvement on Loïc MICHEL's answer, as without -Wait, it's likely that Get-Content will run before the process has finished. As the output isn't written until the process ends, Get-Content fails as the file does not exist.
$param = "ipconfig /all"
$args = "/C $param 2>&1 > C:\temp\test.txt"
Start-Process -FilePath cmd.exe -ArgumentList $args -Verb RunAs -Wait
Get-Content -Path C:\temp\test.txt
Alternatively, using powershell.exe instead and a random file in the temporary directory for the OS:
$CommandWithParameters = "gpresult /scope computer /z"
$OutputFile = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName())
$Arguments = ("{0} 2>&1 > {1}" -f $CommandWithParameters, $OutputFile)
Start-Process -FilePath powershell.exe -ArgumentList $Arguments -Verb RunAs -Wait
Get-Content -Path $OutputFile
Using powershell.exe will save the output file using UCS-2 LE BOM encoding. If you use cmd.exe, the encoding will be ANSI.

Use BAT file to check if PSSnapin is registered

I've hit a little bit of a brick wall here. I have written a rather large PS script that requires the SQLServerProviderSnapin100 and this all works happily.
To run the script I have written a BAT file for the users to run so that they won't have to fiddle around with execuptionpolicy, so it sets it unrestricted calls the script and once the script completes it sets the executionpolicy back to restricted.
The problem I have is that I need the BAT file to detect if the user has the SqlServerProvider100 snapin registered to the 32Bit Powershell or the 64Bit powershell.
I know I could run something like this in powershell
$prov = get-pssnapin -registered | where-object{$_.Name -eq "Sqlserverprovidersnapin100"}
if($prov -eq $null){ <call powershell x86>}else{<call powershell 64Bit>}
But how do I do this in the BAT, or is what I am trying to do even possible?
I hope I making sense to someone who can help me get over this bump! :)
Try these 2 commands:
C:\Windows\Syswow64\WindowsPowerShell\v1.0\powershell.exe "if(Get-PSSnapin -registered "SqlServerCmdletSnapin100" -ea 0){ write-host "sql snapin present in 32bit shell"}"
for 64bit:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "if(Get-PSSnapin -registered "SqlServerCmdletSnapin100" -ea 0){ write-host "sql snapin present in 64bit shell"}"
They will return a pretty message if sql snapin is present.
Ok worked it out!
FOR /F "usebackq delims=" %%i IN (`powershell -command "get-pssnapin -registered | where-object { $_.Name -eq 'sqlserverprovidersnapin100' }"`) DO ( set snapin=%%i )
REM if /i {%snapin:~0,4%}=={%test:~0,4%} (goto :there)
if not defined snapin goto :notthere
(goto :there)
:there
echo %snapin%
pause
exit
:notthere
echo "Not loaded!"
pause
exit
This exercise has taught me two things now: apparently when I was testing against NULL within a BAT, if the value was NULL it would remove the variable and secondly how to pass a PS variable back to BAT.

Resources