When ran with elevated privileges, the code does what it is supposed to do by turning off the laptop's onboard microphone, but it needs to be totally silent. This will be sent out to over 1600 systems. It will be pushed via logon script to the local systems. So it needs to run as Admin and without any user intervention. How do I keep it running elevated and how to get it to run without the UAC prompt?
-TIA
$audioCaptureRegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture"
$MICS = Get-Item $audioCaptureRegPath
$MICS.GetSubKeyNames() | % {`
if($(Get-ItemProperty -Path $audioCaptureRegPath"\"$_).DeviceState -eq 1 ){`
$systemNameData=$(Get-ItemProperty -Path $audioCaptureRegPath"\"$_\Properties).$systemNameVal
if(!($systemNameData -match "plant") -or !($systemNameData -match "HDX"))
{
$tmpFileFullPath = [System.io.Path]::getTempFileName()
"Windows Registry Editor Version 5.00" | Out-File -FilePath $tmpFileFullPath -Append
" " | Out-File -FilePath $tmpFileFullPath -Append
"[$($MICS.Name)\$_]" | Out-File -FilePath $tmpFileFullPath -Append
"`"DeviceState`"=dword:10000001" | Out-File -FilePath $tmpFileFullPath -Append
" " | Out-File -FilePath $tmpFileFullPath -Append
regedit.exe /S $tmpFileFullPath
}
}
}
Related
Pretty sure just me not knowing what to do but I am having issues with a 7zip PS script and the $LastExitCode
ForEach ($File in $Files) {
7zip a “$DestDir\$file.7z” "$SourceDir\$File” -m0=LZMA2 -mx=9 -mmt4 | findstr /I "archive everything error" | Out-File $LOGPath -Force -Append
7zip t "$DestDir\$file.7z" | findstr /I "testing size compressed archive everything error" | Out-File $LOGPath -Force -Append
if ($LASTEXITCODE -eq 0) {
Write-Output “Compression SUCCEEDED and zip file tested OK” | Out-File $LOGPath -Force -Append
Write-Output “DELETING ORIGINAL file - $File `n” | Out-File $LOGPath -Force -Append
Remove-Item -Path “$SourceDir\$File” | Out-File $LOGPath -Force -Append
}
else {
Write-Output “Compression FAILED, source file not deleted `n” | Out-File $LOGPath -Force -Append
}
}
This is the script (important bits)
It does a zip then a test of the created package
So to test that the $LastExitCode is working (or not), I # out the zip part and leave the test step and remove any zip files from the destination folder. The zip test step fails as expected and sends an error to log (Error:cannot find archive) but still goes through with the remove-item, which should only occur if the test passes I would have throught??
Not sure what I am doing worng here? Or if this is the incorrect way to go about this?
I want to create the archive, confirm it is OK, then delete the original source file if it is (i.e. no errors).
Any advice really apprecited
thanks
EDIT
Ended up with below that seems to do the trick - thanks for the advice
ForEach ($File in $Files) {
Write-Output “Compressing $File” | Out-File $LOGPath -Force -Append
7zip a "$DestDir\$file.7z” "$SourceDir\$File" -m0=LZMA2 -mx=9 -mmt4
if ($LASTEXITCODE -eq 0) {
Write-Output "Compression SUCCEEDED" | Out-File $LOGPath -Force -Append
Write-Output “TESTING compressed file - $File” | Out-File $LOGPath -Force -Append
7zip t "$DestDir\$file.7z"
if ($LASTEXITCODE -eq 0) {
Write-Output "Zip file tested OK" | Out-File $LOGPath -Force -Append
Write-Output "DELETING original file - $File `n" | Out-File $LOGPath -Force -Append
#Remove-Item -Path “$SourceDir\$File” | Out-File $LOGPath -Force -Append
}
else {
Write-Output “Zip test FAILED, source file not deleted `n” | Out-File $LOGPath -Force -Append
}
}
else {
Write-Output "Compression FAILED for file - $file - moving onto next file" | Out-File $LOGPath -Force -Append
}
}
This question already has an answer here:
Parameter interpretation when running jobs
(1 answer)
Closed 3 years ago.
I have a running PS1-script (start-webserver.ps1) running as a "web server" that is listening for http calls that executes a script (example: script2.ps1) executed in the call to the "web server".
I am executing the script with Start-Job. How can I in the executed script (script2.ps1) access variables in start-webserver.ps1?
Start-WebServer.ps1
$allObjects = #()
foreach ($item in $items) {
$objectUID = $item.Attributes.Value
$propertiesHash = [ordered]#{UID = $objectUID}
$properties = $items.ChildNodes
foreach ($property in $properties.ChildNodes) {
$propertyName = $property.Attributes.Value
$propertyValue = $property.innerText
$propertiesHash.Add($propertyName, $propertyValue)
}
$object = New-Object PSObject -Property $propertiesHash
$allObjects += $object
}
$job = Start-Job -Name "$identifier" -FilePath "Path\To\ScriptToExecute.ps1" -InputObject $allObjects -ArgumentList $propertiesHash
ScriptToExecute.ps1
'Script executed!' | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
$propertiesHash | Get-Member | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
$allObjects | Get-Member | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
I end up with an "output.txt" with the following content:
Script executed!
Empty line
You need to define in ScriptToExecute that you are receiving params
By default it is set in the $args variable.
In your case, simply using $args[0] will be sufficient.
i.e.:
'Script executed!' | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
$args[0] | Get-Member | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
If you want to also receive $allObjects, you need to modify Start-WebServer to this:
$job = Start-Job -Name "$identifier" -FilePath "Path\To\ScriptToExecute.ps1" -InputObject $allObjects -ArgumentList #($propertiesHash,$allObjects)
then do this:
'Script executed!' | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
$args[0] | Get-Member | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
$args[1] | Get-Member | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
Nicer way of doing this is to specify the param in ScriptToExecute
i.e.:
param($propertiesHash, $allObjects)
'Script executed!' | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
$propertiesHash | Get-Member | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
$allObjects | Get-Member | Out-File -Path ".\output.txt" -Encoding UTF8 -Append
I am attempting to write a powershell script that removes VMware Tools off of physical workstations in my environment (don't ask) while ignoring VMs and I am having issues with the nested if / else statements in the "#Execute VMware Tools removal if physical, then write log" section of this code. Can anyone with more Powershell experience give me some pointers as to what I may have done wrong?
I receive the following error:
else : The term 'else' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
I apologize for the amateur formatting, I am still learning Powershell.
Thank you for any assistance.
#Create log path
$path = "D:\log\folder\location\"
If(!(test-path $path))
{
New-Item -ItemType Directory -Force -Path $path
}
#Gather required host info
$ComputerSystemInfo = Get-WmiObject -Class Win32_ComputerSystem -
ComputerName $env:COMPUTERNAME -ErrorAction Stop
switch ($ComputerSystemInfo.Model) {
# Check for VMware Machine Type
"VMware Virtual Platform" {
$MachineType = "VM"
}
# Otherwise it is a physical Box
default {
$MachineType = "Physical"
}
}
#Execute VMware Tools removal if physical, then write log
if($MachineType -eq "Physical") {
$regpath = "HKLM:\Software\Microsoft\Windows\CurrentVersion\uninstall"
Get-childItem $regpath | % {$keypath = $_.pschildname
$key = Get-Itemproperty $regpath\$keypath}
if($key.DisplayName -match "VMware Tools")
{$VMwareToolsGUID = $keypath} MsiExec.exe /x $VMwareToolsGUID /qn /norestart
{Write-output "VMware Tools Uninstalled" | Out-File -Encoding ascii -filepath "D:\log\folder\location\VMware_Uninstalled.txt"}
else
{Write-output "VMware Tools Not Present" | Out-File -Encoding ascii -filepath "D:\log\folder\location\VMware_Not_Present.txt"}
}
#Write output log if VM
if($MachineType -eq "VM")
{Write-Output "Machine is virtual" | Out-File -Encoding ascii -filePath
"D:\log\folder\location\Virtual_Machine.txt"}
else
{Write-Output "Error" | Out-File -Encoding ascii -FilePath
"D:\log\folder\location\Error.txt"}
I went ahead and made some edits for you so it looks cleaner and fixed your brackets (which was causing the error you are getting). Feel free to ask any questions! As a future reference, the easiest thing to do when you need to check if there is anything wrong with your script you can copy and paste it into PowerShell ISE and it will underline any errors it sees in red.
#Create log path
$path = "D:\log\folder\location"
If(!(test-path $path)){
New-Item -ItemType Directory -Force -Path $path
}
#Gather required host info
$ComputerSystemInfo = Get-WmiObject -Class Win32_ComputerSystem
$Computer = $env:COMPUTERNAME
switch ($ComputerSystemInfo.Model) {
# Check for VMware Machine Type
"VMware Virtual Platform" {
$Global:MachineType = "VM"
}
# Otherwise it is a physical Box
default {
$Global:MachineType = "Physical"
}
}
#Execute VMware Tools removal if physical, then write log
if($MachineType -eq "Physical") {
$regpath = "HKLM:\Software\Microsoft\Windows\CurrentVersion\uninstall"
Get-childItem $regpath | % {$Global:keypath = $_.pschildname
$Global:key = Get-Itemproperty $regpath\$keypath}
}
if($key.DisplayName -match "VMware Tools"){
$VMwareToolsGUID = $keypath
MsiExec.exe /x $VMwareToolsGUID /qn /norestart -wait
Write-output "VMware Tools Uninstalled" | Out-File -Encoding ascii -filepath
"D:\log\folder\location\VMware_Uninstalled.txt"
}else{
Write-output "VMware Tools Not Present" | Out-File -Encoding ascii -filepath
"D:\log\folder\location\VMware_Not_Present.txt"
}
#Write output log if VM
if($MachineType -eq "VM"){
Write-Output "Machine is virtual" | Out-File -Encoding ascii -filePath
"D:\log\folder\location\Virtual_Machine.txt"
}else{
Write-Output "Error" | Out-File -Encoding ascii -FilePath
"D:\log\folder\location\Error.txt"
}
Here is the final script I used if anyone ever needs it.
Thanks to Cory Etmund and briantist for the pointers, time, and knowledge.
#Create log path
$path = "D:\log\folder\location\"
If(!(test-path $path)){
New-Item -ItemType Directory -Force -Path $path
}
#Gather required host info
$ComputerSystemInfo = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $env:COMPUTERNAME -ErrorAction Stop
switch ($ComputerSystemInfo.Model) {
# Check for VMware Machine Type
"VMware Virtual Platform" {
$Global:MachineType = "VM"
}
# Otherwise it is a physical Box
default {
$Global:MachineType = "Physical"
}
}
#Write output log if VM
if($MachineType -eq "VM"){
Write-Output "Machine is virtual" | Out-File -Encoding ascii -filePath "D:\log\folder\location\Virtual_Machine.txt"
exit
}
#Execute VMware Tools removal if physical, then write log
if($MachineType -eq "Physical") {
$regpath = "HKLM:\Software\Microsoft\Windows\CurrentVersion\uninstall"
Get-childItem $regpath | % {$Global:keypath = $_.pschildname
$Global:key = Get-Itemproperty $regpath\$keypath}
}
if($key.DisplayName -match "VMware Tools"){
$VMwareToolsGUID = $keypath
MsiExec.exe /x $VMwareToolsGUID /qn /norestart -wait
Write-output "VMware Tools Uninstalled" | Out-File -Encoding ascii -filepath "D:\log\folder\location\VMware_Uninstalled.txt"
}else{
Write-output "VMware Tools Not Present" | Out-File -Encoding ascii -filepath "D:\log\folder\location\VMware_Not_Present.txt"
}
I have multiple restarts between script blocks, the problem is on every restart the user is required to key in their credentials, and log in.
Is there any way where once the script is being executed it can login to system without username and password? We would want to hardcode username and password in the script itself.
The script helps in achieving the following:
Run Script Block
Restart
Run Next Script Block
But this requires user to log in after restart. Until then the process is under halt. I am looking for a way to automate the login process as well... I know it creates security threat, but this is something that is necessary for the process I am supposed to achieve.
#Code which will run script with admin privileges
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
$arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}
# Temp Folder
if (!(Get-Item d:\temp -ea ignore)) { mkdir d:\temp }
$dropperscript = 'D:\temp\dropper.ps1'
$dropper = #'
#############################################
### Configuration Variables ###
#
# Put any variables you'll use here
#
### ###
#############################################
# Static Variables
$countfile = 'd:\temp\bootcount.txt'
$bootbatch = 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\dropper.bat'
$dropperscript = 'd:\temp\dropper.ps1'
#################
##### Setup #####
# Bootstrap Batch
if (!(Get-Item $bootbatch -ea ignore)) {
$x='PowerShell.exe -Command "& {Start-Process PowerShell.exe -ArgumentList '''
$y=' -ExecutionPolicy Bypass -File "D:\temp\dropper.ps1""'' -Verb RunAs}"'
$x+$y| Out-File $bootbatch -Encoding 'OEM'
}
# Boot Count
if (Get-Item $countfile -ea ignore) {
[int]$bootcount = Get-Content $countfile
if ($bootcount -match "^\d{1,2}$") { ([int]$bootcount) ++ }
else { $bootcount = 1 }
}
else { $bootcount = 1 }
$bootcount | Out-File $countfile
switch ($bootcount) {
1 {
$File="D:\temp\Log.txt"
Get-Date | Out-File $File -Append
Get-Process | Out-File $File -Append
Restart-Computer -Force
##################################################
############### --REBOOT-- ###############
}
2 {
$File="D:\temp\Log.txt"
Get-Date | Out-File $File -Append
Get-Process | Out-File $File -Append
Restart-Computer -Force
##################################################
############### --REBOOT-- ###############
}
3 {
$File="D:\temp\Log.txt"
Get-Date | Out-File $File -Append
Get-Process('\\itdsl\MSNPLAT\Gold\MSNPATCH\msnpatch.exe') | Out-File $File -Append
Restart-Computer -Force
##################################################
############### Restart ################
}
4{
$File="D:\temp\Log.txt"
Get-Date | Out-File $File -Append
Get-Process| Out-File $File -Append
Restart-Computer -Force
##################################################
############### --END-- ################
}
default {
# Dropper is complete; clean up
rm $countfile
rm $bootbatch
rm $dropperscript
}
}
'#
# Drop and run Dropper
$dropper | Out-File $dropperscript -Encoding 'OEM'
Invoke-Expression $dropperscript
I have a scriptblock I would like to run as a background job. Below is the command I would like to run:
Get-ChildItem -Recurse $source | Get-DfsrFileHash | Export-csv -Append C:\Temp\Test_Source_Checksum.csv
If I run this command it goes through successfully with no issues.
I have tried the following for 'Start-Job'
Start-Job -ScriptBlock { Get-ChildItem -Recurse $source | Get-DfsrFileHash | Export-csv -Append C:\Temp\Test_Source_Checksum.csv }
This results in 'Get-Job' displaying as completed, when it actually hasnt, or doesnt appear to have judging by the missing file: 'Test_Source_Checksum.csv'
I have also tried using the following for 'Invoke-Command'
Invoke-Command -AsJob -ComputerName ($env:COMPUTERNAME) -ScriptBlock { Get-ChildItem -Recurse $source | Get-DfsrFileHash | Export-csv -Append C:\Temp\Test_Source_Checksum.csv }
This results in 'Get-Job' displaying failed.
If I display the failure using:
(get-job -name Job38).JobStateInfo.Reason
I get nothing back...
Am I using Start-Job/Invoke-Command incorrectly here?
The reason I would like to run this as a background job is, im trying to copy large amounts of data and checksum it (for a DFS Migration). I would like to copy the data in smaller subsets, then checksum the data which has been copied whilst its copying the next batch over...rinse and repeat
Thanks,
Chris
EDIT:
Here is a copy of the whole script:
##----------------------------------------------------------------------------------##
$source="E:\DFSR_Migration_Test_Prod"
$dest="F:\DFSR_Migration_Test_Prod"
$what = #("/COPYALL","/B","/SEC","/E","/xd","dfsrprivate")
$options = #("/R:6","/tee","/MT:32")
$cmdArgs = #("$source","$dest",$what,$options)
##----------------------------------------------------------------------------------##
robocopy #cmdArgs
Write-Output "Prod_Copied #" (get-date) | Out-File C:\Temp\File_Copy.txt -Encoding ascii -Append -NoClobber
Write-Output "Initiating Prod Source Checksum #" (get-date) | Out-File C:\Temp\File_Copy.txt -Encoding ascii -Append -NoClobber
Start-Job -ScriptBlock { Get-ChildItem -Recurse $source | Get-DfsrFileHash | Export-csv C:\Temp\Prod_Source_Checksum.csv }
Write-Output "Initiating Prod Destination Checksum #" (get-date) | Out-File C:\Temp\File_Copy.txt -Encoding ascii -Append -NoClobber
Start-Job -ScriptBlock { Get-ChildItem -Recurse $dest | Get-DfsrFileHash | Export-csv C:\Temp\Prod_Destination_Checksum.csv }
How are you passing $source? Because if you're doing nothing other than writing the variable name it'll be null, and if it's null you'll be executing Get-ChildItem for $pwd.Path on the remote system.
The simplest solution is to make $source into $using:Source.
Invoke-Command -AsJob -ComputerName ($env:COMPUTERNAME) -ScriptBlock { Get-ChildItem -Recurse $using:source | Get-DfsrFileHash | Export-csv -Append C:\Temp\Test_Source_Checksum.csv }
In addition to the good information above, remember that starting a job is a lot like opening a new console (that you cannot see directly), this means that you may need to re-connect or re-authenticate. As an example, if you want to start a new job that uses PowerCLI, you will have to re-connect to your vCenter Server so in your scriptblock, you would preface your command with (connect-viserver...): start-job -scriptblock {connect-viserver -server <vCenterServer>; powercli command}.