Combining powershell & cmd to create a batch file - powershell

I am not a coder but I have some basic ability to mash some scripts together and usually get something that works for me, but this is way beyond my comprehension. I am trying to combine 3 things into a batch file. It's essentially an all in one solution to turn Windows 10 privacy settings off and to remove some background apps. I can run the commands just fine in powershell, but I wanted to automate the entire thing through one batch script:
Keep the windows 10 privacy settings script up to date. This is done through the following command in powershell:
(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/hahndorf/Set-Privacy/master/Set-Privacy.ps1') | out-file .\Set-Privacy.ps1 -force
Just need to make sure that the destination folder for download is set first (I have no idea how to do this through a batchfile/script). The command comes from the script that someone wrote on github located here
Run the powershell script to turn privacy settings off, on the highest setting. This is done through the following command, again from the link above:
.\Set-Privacy.ps1 -Strong -admin
Remove background apps, for example, removing "3D Builder":
To uninstall 3D Builder:
get-appxpackage *3dbuilder* | remove-appxpackage
Details on this found here
Any help with any of this is greatly appreciated.

Try this, of course PowerShell is not a batch file tool per se, though you can use it to call a batch (.bat,.cmd.vbs, etc.) file.
Though a script is a script (batch or otherwise), taxonomy is a whole different conversation.
So, what you want is a function you can call as needed.
Function Set-Windows10PrivacySettings
{
[CmdletBinding()]
[Alias()]
Param
(
[string]$DownloadPath = "$env:USERPROFILE\Downloads"
)
# Download the Privacy Script
(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/hahndorf/Set-Privacy/master/Set-Privacy.ps1') |
out-file "$env:USERPROFILE\Downloads\Set-Privacy.ps1"
# Temporarialy naviagte to the target directory adn run the script
Push-Location -Path $DownloadPath
Start-Process .\Set-Privacy.ps1 -Strong -admin
# Remove AppX packages
$AppPackageList = (Get-AppxPackage).Name |
Sort-Object |
Out-GridView -Title 'Select one or more AppX to remove. Press CRTL+LeftMouseClick to multi-select' -PassThru
# Remove the selected AppX without prompt to confirm
ForEach($AppPackage in $AppPackageList)
{
"Removing selected AppX $AppPackage"
# Remove-AppxPackage -Package $_ -Confirm:$false -WhatIf
}
# Retrun to the original directory
Pop-Location
}
# Call the function in PowerShell
Set-Windows10PrivacySettings
Just remove the comment marker '#' and the 'WhatIf' switch to actually allow things to happen.

Related

How to save function in powershell?

Hi so i've tried to make my first function. A simple one that will restart powershell in windows terminal. And it's working.
function Restart-PowerShell{
Get-Process -Id $PID | Select-Object -ExpandProperty Path | ForEach-Object { Invoke-Command { & "$_" } -NoNewScope }
But when i restart powershell the function disappear, it doesn't save it. How can i save it? I've tried to look around but couldn't find any way to save
You save PowerShell functions by simply putting their definition in a file on disk:
"function Restart-PowerShell {${function:Restart-PowerShell}}" |Set-Content Restart-PowerShell.ps1
This will write it to a file Restart-PowerShell.ps1 in the current directory.
Next time you need to re-use your function, it's as simple as dot-sourcing the file:
PS ~> . .\path\to\Restart-PowerShell.ps1
PS ~> Restart-PowerShell # now the function is available in the current session
Mathias R. Jessen's helpful answer shows how to save your function's definition to a custom file that you can dot-source on demand in future sessions.
However, there is a file that is dot-sourced automatically when a PowerShell session starts (unless explicitly suppressed with -NoProfile via the PowerShell CLI): your $PROFILE file, and that's where customizations of your sessions - such as custom functions and aliases - are typically stored.
Therefore, if you add your function to your $PROFILE file, it automatically becomes available in future sessions too.
You can open $PROFILE in your text editor or, building on Mathias' technique, add the function programmatically, as follows, which ensures on-demand creation of the file and its parent directory (on a pristine machine, neither exists):
# Make sure the $PROFILE file exists.
If (-not (Test-Path $PROFILE)) { $null = New-Item -Force $PROFILE }
# Append the function definition to it.
#"
function Restart-PowerShell {
${function:Restart-PowerShell}
}
"# | Add-Content $PROFILE
Note: To reload your profile mid-session after having modified $PROFILE, use . $PROFILE.

PowerShell Start-Job not creating or amending files

I am new to PowerShell and this is the first time I am attempting to use a job. I am running into an issue where I have a part of a script that looks for a file, creates it if it doesn't exist and then amends the file, and when I run the script (not as a job) it executes correctly, but when I put it in a job, it doesn't amend the file.
A much simplified example of what I have is this:
Start-job -Name HostCheck -ScriptBlock {
ForEach ($Host in (Get-Content -Path .\HostFile.txt) {
Add-Content .\somefile.txt "`nWrite something on a new line for $Host"
} | Out-Null
}
# Removes job once it is finished
Get-Job -Name HostCheck | Wait-Job | Remove-Job
Now I have tried adding | Receive-Job after the | Out-Null, but that didn't seem to change anything.
I've seen people write the entire script-block to a variable and just use the variable instead, so I am curious if that is a requirement (but I wouldn't think so).
Also, this might matter, I open the script with a .bat file that escalates the PowerShell console to admin as well as setting the execution policy of the process to Bypass. Now it seems that everything that runs in that console session or is kicked off by that console session (several scripts get ran, this is just part of one of them) seems to inherit those settings, but being new with jobs, I don't know if it would also inherit those settings, or how I would force it to (if not).
I discovered the problem:
-Your current working directory is lost when starting a job so my relative path .\somefile.txt would default to C:\Users\[Username]\Documents instead of the location where the .\somefile.txt resides.
I can get around this by using an absolute path, or I think there is a way to pass arguments to a job, but if anyone knows a better way to do this, please feel free to comment.
Here's a workaround, cd to the current dir of the caller.
start-job { cd $using:pwd; pwd } | Receive-Job -wait -auto

Powershell - shortened the directory prompt, but how to save the change?

Using Powershell in Windows 10. To change the prompt from:
PS C:\Users\b.HQ\Desktop\tsdev\my_folder>
PS my_folder> tsc
I used the following command in Powershell:
function prompt {'PS ' + $(Get-Location | Split-Path -Leaf) + ">"}
But, each time I restart Powershell, I have to reenter this. Is there any way to persist this change?
P.S. I know nothing about the config of Powershell, and I have looked for a solution, but apart from the prompt I am using, I did not see a way of saving it.
Run powershell as administrator, then run the following:
Test-Path $Profile
if it returns false then no you don’t have a profile file yet, so create it:
New-Item –Path $Profile –Type File –Force
(this will create profile file, or will overwrite the existing one)
Then, edit your profile file:
notepad $Profile
put your function in the file and save.
I created this neat prompt to that shows the drive and last folder.
For you example it would render as
PS C:\Users\b.HQ\Desktop\tsdev\my_folder>
as
PS C:\...\my_folder>
The prompt function is:
function prompt {"PS " + (get-location).drive.name+":\...\"+ $( ( get-item $pwd ).Name ) +">"}

how to use wmi with powershell to target a specific printer for output

I have an amazing script i am going to use to for a bespoke print solution. There is one thing left to do. The script utilizes Start-Process –FilePath “c:\testfolder\*.docx” –Verb Print
how can i make it so it targets an installed printer on the client system without targeting/using the default printer? (another VBScript already uses the default).
PSVersion5. + W764bit
(New-Object -ComObject WScript.Network).SetDefaultPrinter('Xerox Floor X')
This does the trick, it will select the relevant default printer and then i can run another line which will default it back to the original default printer after the script runs.
Some issues with parentheses running and defaulting it back before it prints at the moment though.
I dont think you can specify the printer when using the Print verb. What you can do is this:
Get-ChildItem -Path "C:\testfolder" -Filter *.docx | Out-Printer "\\Server01\Prt-6B Color"
Get all items in path with extension .docx pass to Out-Printer
More on Out-Printer

PowerShell: Run command from script's directory

I have a PowerShell script that does some stuff using the script’s current directory. So when inside that directory, running .\script.ps1 works correctly.
Now I want to call that script from a different directory without changing the referencing directory of the script. So I want to call ..\..\dir\script.ps1 and still want that script to behave as it was called from inside its directory.
How do I do that, or how do I modify a script so it can run from any directory?
Do you mean you want the script's own path so you can reference a file next to the script? Try this:
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Write-host "My directory is $dir"
You can get a lot of info from $MyInvocation and its properties.
If you want to reference a file in the current working directory, you can use Resolve-Path or Get-ChildItem:
$filepath = Resolve-Path "somefile.txt"
EDIT (based on comment from OP):
# temporarily change to the correct folder
Push-Location $dir
# do stuff, call ant, etc
# now back to previous directory
Pop-Location
There's probably other ways of achieving something similar using Invoke-Command as well.
There are answers with big number of votes, but when I read your question, I thought you wanted to know the directory where the script is, not that where the script is running. You can get the information with powershell's auto variables
$PSScriptRoot # the directory where the script exists, not the
# target directory the script is running in
$PSCommandPath # the full path of the script
For example, I have a $profile script that finds a Visual Studio solution file and starts it. I wanted to store the full path, once a solution file is started. But I wanted to save the file where the original script exists. So I used $PsScriptRoot.
If you're calling native apps, you need to worry about [Environment]::CurrentDirectory not about PowerShell's $PWD current directory. For various reasons, PowerShell does not set the process' current working directory when you Set-Location or Push-Location, so you need to make sure you do so if you're running applications (or cmdlets) that expect it to be set.
In a script, you can do this:
$CWD = [Environment]::CurrentDirectory
Push-Location $MyInvocation.MyCommand.Path
[Environment]::CurrentDirectory = $PWD
## Your script code calling a native executable
Pop-Location
# Consider whether you really want to set it back:
# What if another runspace has set it in-between calls?
[Environment]::CurrentDirectory = $CWD
There's no foolproof alternative to this. Many of us put a line in our prompt function to set [Environment]::CurrentDirectory ... but that doesn't help you when you're changing the location within a script.
Two notes about the reason why this is not set by PowerShell automatically:
PowerShell can be multi-threaded. You can have multiple Runspaces (see RunspacePool, and the PSThreadJob module) running simultaneously withinin a single process. Each runspace has it's own $PWD present working directory, but there's only one process, and only one Environment.
Even when you're single-threaded, $PWD isn't always a legal CurrentDirectory (you might CD into the registry provider for instance).
If you want to put it into your prompt (which would only run in the main runspace, single-threaded), you need to use:
[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem
This would work fine.
Push-Location $PSScriptRoot
Write-Host CurrentDirectory $CurDir
I often used the following code to import a module which sit under the same directory as the running script. It will first get the directory from which powershell is running
$currentPath=Split-Path ((Get-Variable
MyInvocation -Scope
0).Value).MyCommand.Path
import-module "$currentPath\sqlps.ps1"
I made a one-liner out of #JohnL's solution:
$MyInvocation.MyCommand.Path | Split-Path | Push-Location
Well I was looking for solution for this for a while, without any scripts just from CLI. This is how I do it xD:
Navigate to folder from which you want to run script (important thing is that you have tab completions)
..\..\dir
Now surround location with double quotes, and inside them add cd, so we could invoke another instance of powershell.
"cd ..\..\dir"
Add another command to run script separated by ;, with is a command separator in powershell
"cd ..\..\dir\; script.ps1"
Finally Run it with another instance of powershell
start powershell "cd..\..\dir\; script.ps1"
This will open new powershell window, go to ..\..\dir, run script.ps1 and close window.
Note that ";" just separates commands, like you typed them one by one, if first fails second will run and next after, and next after... If you wanna keep new powershell window open you add -noexit in passed command . Note that I first navigate to desired folder so I could use tab completions (you couldn't in double quotes).
start powershell "-noexit cd..\..\dir\; script.ps1"
Use double quotes "" so you could pass directories with spaces in names e.g.,
start powershell "-noexit cd '..\..\my dir'; script.ps1"