If you can Invoke-Command to a remote system, you can just pass plain PowerShell code in a script block without having to wrap it in another call to powershell.exe like that. Invoke-Command uses WinRM to execute PowerShell directly on the target machine, unlike PSExec which installs a temporary service to start an arbitrary process on the target. Also, if you can Invoke-Command on the target machine, you don't really need to change execution policy at all, because you're already executing PowerShell code on the machine at that point. So instead of this: code:
code:
code:
nielsm fucked around with this message at 22:27 on Jul 18, 2016 |
|
# ¿ Jul 18, 2016 22:21 |
|
|
# ¿ May 14, 2024 22:14 |
Invoke-Command can also take a -FilePath argument instead of -ScriptBlock. When you use -FilePath, the path is local and not remote, so you don't have to copy the script over. Do get used to reading the manual pages. They tend to be quite detailed especially for the core commands: https://technet.microsoft.com/library/hh849719.aspx
|
|
# ¿ Jul 19, 2016 06:05 |
Funny reasoning, because WinRM is far more secure than PSExec. Or are you just copying files over than walking up to each workstation?
|
|
# ¿ Jul 23, 2016 10:10 |
Get-ADUser grabs very little data by default. If you need more than the limited default set, use the -Properties parameter to specify what fields you want. Or just use "-Properties *" to get everything.
|
|
# ¿ Jul 28, 2016 16:02 |
BaseballPCHiker posted:Do you have WinRM configured? Have you verified you have the rights for that PC? PSExec doesn't use WinRM.
|
|
# ¿ Aug 3, 2016 19:04 |
Specifically, for PSExec to work, you must have a user account that can connect to \\COMPUTER\ADMIN$ and write files there. You also need to be able to run "sc \\COMPUTER create <parameters>" to control the service control manager on it. PSExec uses those remote management tools to do its task.
|
|
# ¿ Aug 3, 2016 19:29 |
I believe PowerShell loads the full script, then closes the script file, letting you delete the file without problems, even in the middle of execution. DOS-derived batch files traditionally execute line by line, with the result that you could, at least under true DOS, have a batch file that modifies itself while running. I don't know how cmd.exe does things, but you should be able to delete a running batch file, just don't expect it to be able to continue running afterwards.
|
|
# ¿ Aug 9, 2016 20:46 |
If you wrap your task with a function, or even a module, and then have a small runner script that invokes it, you can use standard redirection on that. Make sure to read Get-Help about_Redirection.
|
|
# ¿ Aug 16, 2016 17:30 |
22 Eargesplitten posted:Now my question is how to find registry keys by value. I've got server entries in the registry, so I want to be able to search for a particular value and replace all instances of that value with the new server name. The Google searches I have done are only bringing up searches for the key name, not the value. First, do you actually mean keys, or do you actually mean values? Keep in mind that the registry has this odd structure where the "folders" are called keys, and each key has a number of values. A value has a name, a datatype, and data. The values are the "files". (Historically, there was only one value per key, the one now represented with a blank/null name, shown as (Default) in regedit.) Anyway, first figure out if you're looking for keys, or for key+value name. And whether you're searching by value data or something else. When you use Get-ChildItem in a registry provider tree in PowerShell (e.g. HKLM:\ ) then you only get the keys out as objects, the values are accessed roundabout through the keys. You can do something like this, at least: code:
|
|
# ¿ Sep 9, 2016 23:18 |
22 Eargesplitten posted:I guess I'm looking for the value data then? My lead admin calls the values keys, if I'm understanding you right. He calls the individual items you edit keys. I'm not surprised, though. Everyone here calls display port "Dell DVI" and it drives me crazy. My example searches for keys ("folders") that have a value named "PerceivedType" with a data contents of "video". E.g. for this, it would find the "HKLM:\SOFTWARE\Classes\.MKV" item:
|
|
# ¿ Sep 10, 2016 00:07 |
beepsandboops posted:I want to shoot off a command to our on-prem Exchange and Lync servers as part of our new user script. I can definitely use Invoke-Command to run individual cmdlets on Exchange, without importing the session or making a module from it. I just connect the session with New-PSSession, usually using -Name to set a name for the session so I can easily grab it later with Get-PSSession. (Actually I have a custom Get-ExchangeSession function that tries to get the named session, and if that fails then it establishes one with that name and returns it.) Then just store the session reference into a variable and pass that for -Session on Invoke-Command. I can post an example tomorrow when I'm at work.
|
|
# ¿ Sep 26, 2016 20:50 |
Basic example of doing Exchange management via Invoke-Command instead of an imported PSSession:code:
|
|
# ¿ Sep 27, 2016 09:47 |
milk milk lemonade posted:I'm writing a password reset script and I figured out how to get it to say "Sorry! That user doesn't exist" but I want it to return to the start of the script when that happens. Is there an easy way to do this? I've looked at a few things like erroraction but I don't think this applies when I do GetADUser and want it to either display the results or say "whoops!". If I need to start over and look at it from another angle I'd appreciate any tips on where to start! Look into how classic text-mode menu systems have been written. The typical approach is to have an "input loop" for each "menu" or other input-step, that will take input from user, validate it, and only exit the loop when a valid input has been received. Roughly, untested and maybe incorrect: code:
|
|
# ¿ Nov 1, 2016 16:33 |
Frohike999 posted:Ok, I'm hoping one of you can help with this one. I'm trying to write a script that will recursively go through a folder and rename all the files in it. That part I'm ok with. The problem I'm having is how to actually do this rename. The files all have the format of "abc1234.txt'. I want to keep the abc prefix and the .txt, but I want to add 100000 to the number in the middle. It's not necessarily always a 4 digit number in the middle, it could be abc1.txt or abc100001.txt. I'm going to keep working on this at work this morning, but if anyone has any insight I'd really appreciate it. A regular expression may work to extract things. code:
pre:PS> "abc123.txt" -match "(abc)(\d+)(\.txt)" True PS> $Matches Name Value ---- ----- 3 .txt 2 123 1 abc 0 abc123.txt PS> $Matches[1] + ([int]$Matches[2] + 1000000) + $Matches[3] abc1000123.txt
|
|
# ¿ Dec 14, 2016 13:21 |
The Right thing to do would be wrapping the tasks you want to do in a Powershell module, then write a C# app calling that module through the Windows.Automation namespace.
|
|
# ¿ Dec 21, 2016 00:16 |
GPF posted:You've got me all hot and bothered now. Could you drop an example? Here's a simple one: GUI is box with button and display area. Button fires off module that does a Get-Service on the local system. Returned list is dropped into the display box. Here's a stupidly simple WPF app that lists services I don't know if the project files will work on any other machine, I picked a random System.Management.Automation.dll inside WinSxS for the reference.
|
|
# ¿ Dec 23, 2016 22:23 |
On the other hand, I think if you need to make pipelines, things become much more complex. Which is why you definitely want to pack all your logic into a module beforehand, so you only need a thin layer of glue in the GUI. You can also set up "runspaces" in the programming model to do remoting directly. Unfortunately, it seems the security aspects of remoting can be difficult, at least if you want to target Exchange. I experimented with setting that up once, and never found something that worked.
|
|
# ¿ Dec 24, 2016 01:17 |
cheese-cube posted:What security aspects of Exchange remoting did you find difficult? I can make it work just fine against our on-prem Exchange through regular Powershell. But when i tried establishing a runspace with the same parameters via the API in C#, it failed connecting in various ways. I can't remember the details, but there's no HTTPS configured or the cert is invalid, and it refuses to let me trust it regardless, giving various odd errors. Sometimes even claiming the server name not existing despite DNS working perfectly fine everywhere else.
|
|
# ¿ Dec 24, 2016 08:57 |
Likely since that allows them to guarantee the algorithmic complexity. When both inputs are sorted on the same criteria, the algorithm needs to do at most M+N comparisons, and the inputs can even be forward-only iterators or generators instead of being random access lists. So from a CS standpoint, it makes good sense.
|
|
# ¿ Jan 6, 2017 00:16 |
Avenging_Mikon posted:
And similar, HKLM = HKEY_LOCAL_MACHINE, HKCR = HKEY_CLASSES_ROOT (which it's important to remember is not a real key, but a combined view of HKLM and HKCU subkeys Software\Classes).
|
|
# ¿ Feb 8, 2017 16:50 |
No idea about that, but I've always just used the + operator to assemble strings when needed. Or string interpolation to glue contents of variables into strings.code:
|
|
# ¿ Mar 5, 2017 20:58 |
I can't remember the terms to search for here, so can't find an answer... I have a bunch of WMI objects I want to pass to Remove-WmiObject -Confirm, but the identity displayed for each is useless to the operator. Is there a way to override the "short display string" or whatever it's called for an object? code:
pre:Confirm Are you sure you want to perform this action? Performing the operation "Remove-WmiObject" on target "\\machine\root\cimv2:Win32_UserProfile.SID="S-1-5-18"".
|
|
# ¿ Mar 20, 2017 14:12 |
PBS posted:That output is the result of what is being passed to the method used for confirmation. Without changing the target yourself, I don't think you can change what's displayed for the confirmation without modifying those cmdlettes. I think it uses obj.ToString() to get the identity shown, but really no idea. I'm not sure if it's even documented. The problem with manually iterating over the objects is that you can very easily break "Yes to All" and "No to All" which are important to have in this use case. But I think maybe writing a cmdlet of my own that just wraps Remove-WmiObject but somehow causes a more useful object identity to be printed, could work.
|
|
# ¿ Mar 20, 2017 19:55 |
Yes, Get-ADGroupMember returns you sparsely populated generic AD objects, since groups can contain just about any kind of object as member. If you know only users are members of the group, you can safely pass the result of that straight into Get-ADUser to get all the details, optionally passing -Properties to Get-ADUser to get more than the default property set. For example:code:
|
|
# ¿ Mar 30, 2017 18:18 |
Avenging_Mikon posted:whoops, didn't even notice that part. Well, I'm taking what I've learned and am now making a script to disable AD accounts and update their description with the date they were disabled. Plain text: Get-Content -Path "c:\some\file.txt" -Encoding UTF8 CSV: Import-Csv -Path "C:\some\file.csv" -Header @("UserName","FirstName","LastName","Email")
|
|
# ¿ Mar 31, 2017 21:48 |
Collateral Damage posted:Dumb question time: Some times when concatenating variables I see people use $($variable) and some times just $variable. What's the difference? The former lets you concatenate with variable-name-valid characters right of the name. E.g.: "Free space: $(variable)MB" If you wrote "$variableMB" it would look for a variable actually named variableMB instead. Actually, what it really does is let you put entire expressions inside an interpolated string, so you can do things like: "Free space: $($freeSpace/$totalSpace*100)%"
|
|
# ¿ Jun 1, 2017 14:55 |
I certainly think the parentheses makes it easier to pick out when reading code without syntax highlighting, too.
|
|
# ¿ Jun 1, 2017 15:14 |
You're not passing the credential you prompt for to the Exchange session, so it gets logged in with the account you're running PowerShell under (probably your regular domain account). If you need to use a different login to get administrative access, make sure you're actually passing $credentials to New-PSSession.
|
|
# ¿ Jun 2, 2017 17:06 |
Can't test right now, but basically something like -Filter "accountExpires -lt '2017-07-05'" should work.
|
|
# ¿ Jul 5, 2017 18:00 |
cheese-cube posted:Also what version of PS are you using? Can you just use the native Get-Acl and Set-Acl cmdlets? I think the point is that constructing an ACL manually for use with Set-Acl is somewhat difficult.
|
|
# ¿ Aug 29, 2017 18:34 |
Avenging_Mikon posted:2. I would like the script to ask me for the User's ID, and the ticket number. The best approach (IMO) is to declare these as parameters, that way you can also call your script as part of another script, with the "host script" supplying the values instead of being locked in to interactive prompting. I assume your script is a .ps1 file you run by itself. Put this block at the very top: code:
You can do a lot more with parameters, but this is the most basic. Read up on the param() block as well as on the Read-Host cmdlet. This way you can both call your script as "interactive" (e.g. right-click in File Explorer and choose Run, or click the Run button in the ISE), or you can call it with parameters from the prompt, like: .\DisableUser.ps1 -UserID fred -TicketID SDE0023523 nielsm fucked around with this message at 21:22 on Aug 29, 2017 |
|
# ¿ Aug 29, 2017 21:18 |
I'm wondering if there are some idioms or syntaxes I'm missing, working with the regular MS ActiveDirectory module. Say I have a list of user names, and a list of group names. I want to know what users are not in each group, and I want to simply add the missing users. Using Add-ADGroupMember with -Members @("user1", "user2") fails if even a single of the users is already member of the group, and making a loop (ForEach-Object) over the users is awkward and seems backward. Is there a better way? Is there a good way to present a table (matrix) of AD user objects (with MemberOf property fetched) with some select groups as columns, containing member true/false flags? One that doesn't involve a loop and Add-Member (or creating PSCustomObjects).
|
|
# ¿ Nov 14, 2017 12:54 |
Or splat it:code:
|
|
# ¿ Dec 29, 2017 23:36 |
I'm using New-ADGroup -WhatIf regularly as part of a script, works fine.
|
|
# ¿ Feb 10, 2018 10:56 |
Volume shadow copy on the file server gives you instant-to-take snapshots of the entire file system, and lets you/users restore files directly from File Explorer. It's the best thing ever for getting out of "oops data gone" situations. It's called Previous Versions in File Explorer.
|
|
# ¿ Feb 23, 2018 23:29 |
https://mcpmag.com/articles/2013/08/20/powershell-name-duplicates.aspx talks about exactly that problem, you can specify a prefix in Import-Module that gets appended to the noun part: Import-Module Hyper-V -Prefix Hv Import-Module VMware.VimAutomation.Core -Prefix Vmw That should get you commands named Get-HvVMHost and Get-VmwVMHost instead. ^^^ but that module "namespace" prefix sounds like a perhaps better solution.
|
|
# ¿ Mar 27, 2018 20:33 |
Implement your GUI as a .NET class library and import that into Powershell.
|
|
# ¿ Mar 29, 2018 09:16 |
Zaepho posted:Powershell only allows you to do things you already have rights to do. Also, it essentially encapsulates .Net so to really block things you'd have to block .Net. Which of course you would never do because it's pretty much essential. This. If PowerShell lets someone do a thing they should not have permissions to do, it's not PowerShell that's at fault. The permissions on the affected thing were set up were wrong to begin with. (Also, fun fact: A base installation of the .NET framework includes a full functioning C# compiler, C:\Windows\Microsoft.NET\Framework\version\csc.exe. Anyone who can create files and run arbitrary programs can use that to compile their own code and do anything PS could be used for.)
|
|
# ¿ May 21, 2018 21:30 |
I'm not sure any filesystem supports prepending data to a file without rewriting the entire file. What the above code does is turn this: 1234567890 into this: x234567890 Same length, just the first byte replaced. When you say "preappending" I think of getting this result instead: x1234567890 That always requires reading the entire file. You won't need to read it all into memory at once, but you will need to read it all off disk and write it all back. (In Unix you can open() the original file, unlink() the name from the inode while keeping the file open, open() the filename again creating a new file, write the data to prepend, then read blocks of the original file and write those to the new file until EOF. When done, close both original files, and the original file really disappears because there's no more links to the inode in form of either names or file handles. I'm not sure if Windows supports something exactly equivalent.)
|
|
# ¿ Jun 1, 2018 18:21 |
|
|
# ¿ May 14, 2024 22:14 |
Only < > & are "core" to XML, anything else technically has to come from a DTD or other external source. There's nothing wrong with leaving a character unencoded if the meaning is unambigious.
|
|
# ¿ Aug 3, 2018 07:30 |