|
So, this may sound dumb, and that's probably because it is, but uhhh let me kinda describe what I do and what I'm thinking about doing about that, so please give me enough room to hang myself before you bring out the pitchforks. My team's sole focus is deploying install scripts through CM for enterprise deployment and we are like 95%+ PowerShell, with a tiny fraction of MSIs (I've done like 1 or 2 MSIs in my first year). We have 5 people on the team and 1 shared "Standard" library that we include with like... sets up a few variables and logging, and has a handful of poorly documented "common" functions. Otherwise, I'm just sort of left to code each new thing from scratch, in part because this team moved over from WISE Scripting a few years back and a lot of the code from the 1st couple of years of PowerShell has not... aged gracefully. All our applications are stored on a big ol' network share, scripts and payloads and everything, for posterity. I'm free to paw through and use anything I like, but that's largely dependant on having the institutional knowledge to know how each app was done to find stuff for reuse, and again, a lot of the older stuff isn't great. My working theory is to beg a bitbucket setup off the team that manages that (even though it's not really supposed to be used for this), and at least getting all our PS code up into it, so we've got something reasonably searchable so maybe there's a little more standardization and a little less reinventing the wheel. I won't be able to put all the payload files up there, I expect, but maybe I can also export all the applications from CM and throw the XML up there as well (we've really only just started actually exporting and removing old obsolete CM applications, we had ~7 years of Everything Ever Written still clogging up CM before Microsoft put their foot down and told us the servers were keeling over and they weren't going to be able to support our infrastructure if we kept doing that). Does any of this sound logical? I've got a lot of management and team goodwill I can burn, but effectively a $0 budget, and probably a million security restrictions, but I can't see us all just operating our 5 little independent code fiefdoms forever.
|
# ? Jun 24, 2021 03:21 |
|
|
# ? May 14, 2024 19:17 |
|
Get stuff organized into repos ASAP. If your org is already on bitbucket it’s probably fine but Azure devops is free for 5 users and you’ll get some lightweight project management, repos, and pipelines. Azure devops pipelines work amazingly well as task runners.
|
# ? Jun 24, 2021 03:59 |
|
The Fool posted:Get stuff organized into repos ASAP. If your org is already on bitbucket it’s probably fine but Azure devops is free for 5 users and you’ll get some lightweight project management, repos, and pipelines. Thanks. I know like... 1 of those words, but I'll start looking into it. I'm here for the next 20ish years, most likely, so I've got time to grow it. I don't think we're going to get any MS stuff for free, even if only my team of 5 wanted to use it, though. But if I figure out what I'm doing, I can probably get any MS thing eventually, since we've got like a literal billion dollar MS contract.
|
# ? Jun 24, 2021 04:05 |
|
Toshimo posted:So, this may sound dumb, and that's probably because it is, but uhhh let me kinda describe what I do and what I'm thinking about doing about that, so please give me enough room to hang myself before you bring out the pitchforks. I was in sort of your position 6 years or so ago, and your steps seem pretty logical. Here is, personally, some concrete steps I would try - you're effectively trying to move your team from a disconnected bunch of people to a dev team Gitlab offers free private repos as well and has a bit more of a mature devops stack too if you ever get into that. It's my personal favorite nowadays. regardless... 1. Organize all your stuf into a repo. 2. give it some sort of structure! Maybe around ... program install type? Developer? Doesnt matter! 3. set a default branch! 4. tell folks to MR/PR in requests for new code, and let everyone peer review them to both spread knowledge/best practices/code reuse! 5. Start insisting documentation - powershell has pretty good built in documentation abilities in their scripts' 6. Setup a template everyone should use for their script that pull in the (hopefully now) better documented common functions 7. More Advanced: you can add gitlab/ADO runners that do stuff like static code analysis to check for best practices when people put in PRs and install scripts! 8. Even More Advanced: eventually, you can on merge have it automatically deploy the script/package to CM and setup the advertisement (that whaat they still call it?) package, etc on merge .. and nobody ever manually touches the CM console ever again, all done through code
|
# ? Jun 24, 2021 04:06 |
|
Yeah, like today I wanted to stop a service in a script and I was like... I think I remember doing this before but idk which script it was in. So, I had to think it all out and do it all in steps because you can't just "stop a service". It's:
And then do it all in reverse at the end of the script to start the service again. I set myself a reminder to pull that code out and save it in my snippets folder at the end of the week (I've been in PowerBI training all week so, my bandwidth until Friday is limited or I'd do it while it's fresh).
|
# ? Jun 24, 2021 04:16 |
|
Toshimo posted:Yeah, like today I wanted to stop a service in a script and I was like... I think I remember doing this before but idk which script it was in. So, I had to think it all out and do it all in steps because you can't just "stop a service". for stuff like this it's really a good idea to keep an index of your functions and what you do - like a README.MD in the directory. Also, naming conventions help, I try and followed powershell's own suggestions. And then organization in a module.. which you can import into your script and use over again yay Public documentation of your own "internal api" of stuff is for sure one of the best benefits of getting a template/index/naming convention
|
# ? Jun 24, 2021 04:26 |
|
Toshimo posted:We have 5 people on the team and 1 shared "Standard" library that we include with like... sets up a few variables and logging, and has a handful of poorly documented "common" functions. Otherwise, I'm just sort of left to code each new thing from scratch, in part because this team moved over from WISE Scripting a few years back and a lot of the code from the 1st couple of years of PowerShell has not... aged gracefully. I'm going to address just this bit here. If y'all aren't using https://github.com/PSAppDeployToolkit/PSAppDeployToolkit you should really take a look at it. It may help with a ton of the common library stuff. It also helps encourage building uninstalls alongside the installs.
|
# ? Jun 24, 2021 14:39 |
|
Zaepho posted:I'm going to address just this bit here. If y'all aren't using https://github.com/PSAppDeployToolkit/PSAppDeployToolkit you should really take a look at it. It may help with a ton of the common library stuff. It also helps encourage building uninstalls alongside the installs. We absolutely are not, and I'll take a look at it, thanks. Part of the problem with moving the group wholesale to any new platform at this point is that we're very beholden to a lot of legacy logging requirements (self-inflicted, not mandated by management), so everything has to log "just so". Unfortunately, each team member does it ~just a little differently~ and even vary it up by script, which is part of why I want to standardize. I figure it's probably a three-step process at this point (for that particular thing): Step 1 is getting all our shared code synched up; Step 2 is to start finding a library system to move to so we aren't writing it ourselves all the time; Step 3 is to migrate our logging to use something compatible with the new system. A good example of a basic problem I'm trying to fix:
I was asked during QC on a script by our senior team member why I had a line at the end of my script that returned a slightly verbose text description with my return code stone point, and I replied that I thought it was good practice to put something in the short, public-facing log that would be informative to the casual observer, and that I was a bit concerned that a lot of them were empty or just a return code. He replied with "I don't know the last time I ever looked at one of those short logs, we just go straight to the verbose ones". I told him that we had 100,000 users and that there were 5 of us, so I thought it was important for the other 99,995 people who would look at a log to have something meaningful, especially if they were reporting a problem to the help desk. He's a pretty good guy, and said he'd look into updating our standard template to have a more standardized default message in the short log, thankfully, but it's very much just one thing on the Big Pile of Cruft That Needs Addressing.
|
# ? Jun 24, 2021 15:50 |
|
I mean that sounds awful. I would suggest just using something like NLog which is a very popular, widely use .NET logging framework with powershell and let it handle most of that for you. its not super hard to use with powershell. I havnet used it but Poshlog uses serialog and looks really nice. Serialog is the other super full featured .net logging framework that everyone uses. but all of them by default let you do things like send only error messages to a specific log and verbose/debug/info to another log file. and they stream write as the script runs,etc. They also support a million different datasources - not just text files but hooks into sql, the console, and other third party log aggregation frameworks like ELK
adaz fucked around with this message at 16:03 on Jun 24, 2021 |
# ? Jun 24, 2021 15:59 |
|
I mean, I count myself thankful that we do do a bunch of logging, and QC, and testing, and a number of other helpful things, even if we aren't exactly at Best Practices level, yet. And that the team and management are both pretty receptive to change (although preferably incremental). And sometimes the stuff catches me doing stuff that I can do better, even if it's Not Wrong. Like, I had a recent script where I was removing some item properties, and I just wanted them gone, didn't really care if the item had the properties in the first place. So, I just Removed them, and let PS catch the exception. Not So Fast. Even though I was catching the exception and even though it didn't matter that I was trying to remove something that didn't exist, it started bloating up the super verbose transcript log with Informative Error Messages. So, I just added a quick check for existence, and now my logs are clean. I guess it's Technically More Correct this way, even if there's no actual practical difference, but I'd rather get nudged towards being a little more meticulous every now and then, if it also catches me when I Legit gently caress Up.
|
# ? Jun 24, 2021 16:14 |
|
If my "CM" you mean MEMCM (formerly but not actually SCCM) aka ConfigMgr, then you can also log in a format that CMTrace will understand, because odds are good you'll be comfortable with it, and you know it will be there if you're troubleshooting deployments.
|
# ? Jun 24, 2021 16:25 |
|
FISHMANPET posted:If my "CM" you mean MEMCM (formerly but not actually SCCM) aka ConfigMgr, then you can also log in a format that CMTrace will understand, because odds are good you'll be comfortable with it, and you know it will be there if you're troubleshooting deployments. I will deliver to you the unfortunate news that writing code that returns meaningful data to SCCM/MEMCM/ConfigMgr has at some point been dismissed as an option because "it was just not actually reading the return codes anyway" or something. It's another thing on the pile for me to investigate.
|
# ? Jun 24, 2021 16:29 |
|
I'm not talking about returning data to MEMCM, I'm talking about writing logs in a formation that CMTrace will understand: https://janikvonrotz.ch/2017/10/26/powershell-logging-in-cmtrace-format/ If you're not familiar with/aware of CMTrace then look for it in C:\Windows\CCM\CMtrace.exe and use it to open up some logs in C:\Windows\CCM\Logs and be amazed at its capability.
|
# ? Jun 24, 2021 16:31 |
|
CMTrace y'all are bringing back MEMORIES of years ago of debugging CCMEXec logs <3
|
# ? Jun 24, 2021 16:37 |
|
The tail -f of Windows!
|
# ? Jun 24, 2021 16:44 |
|
I know there's a way to do it but for whatever reason my brain and searching are failing me: how does one succinctly build a list of search results from three or more arrays looking for a match in object property? I have a number of Select-String search results and need to capture the filename, line number, and line content so obviously just keeping the MatchInfo object onhand is a good idea. The trick is they want to search for multiple patterns that are match. For doing it with two it's relatively simple but I'm brainfarting on the best way to do more in a scalable way. The idea would be you'd hunt for "foo", "bar", and "buzz" and if two different files existed that contained all of them you'd get back 6 results (the MatchInfo values for 3 hits on 2 files). Any thoughts?
|
# ? Jul 12, 2021 21:32 |
|
PierreTheMime posted:I know there's a way to do it but for whatever reason my brain and searching are failing me: how does one succinctly build a list of search results from three or more arrays looking for a match in object property? Something like this? code:
|
# ? Jul 12, 2021 22:59 |
|
New Yorp New Yorp posted:Something like this? Well, the issue is that I need to match it on the filename property specifically, the other values of the object may differ because the same file name might exist in different places across difference file systems. Basically someone made a whole bunch of scripts and never kept track of them and now they want to be able to search which scripts contain shared resources so they know if any changes/migrations might impact others. Edit: I can probably just use multiple patterns in Select-String now that I think about it, I'll tinker around. PierreTheMime fucked around with this message at 23:14 on Jul 12, 2021 |
# ? Jul 12, 2021 23:06 |
|
Crosspost from the programming thread: Not sure if PowerShell questions are considered programing related but I'd like to see if anyone can offer advice. This also is in Azure so that may further isolate me on this. I'm trying to loop through all of my Azure subscriptions and pull automation account expiry date information. I can get this to work with single subscriptions but when I try it with multiple subs, it only returns data from the last sub processed. The issue seems to be keeping the subscription context through the lower loops. I have similar issues if I nest the loops or run them sequentially. The initial ForEach loop works, it grabs all resource groups from all subscriptions. When I pass it the results on to the next ForEach, that is when it loses the context switching. Any advice is appreciated. code:
Luna fucked around with this message at 20:27 on Jul 16, 2021 |
# ? Jul 16, 2021 20:24 |
|
Luna posted:Crosspost from the programming thread:
Does this work any better? code:
|
# ? Jul 16, 2021 21:08 |
|
$AAs gets overwritten with each loop over $RGs, so it makes sense that only the last retrieved value is available. Also, building arrays and looping with foreach..in feels awkward in PS rather than using the pipeline. Try something like: code:
|
# ? Jul 16, 2021 21:13 |
|
Toast Museum posted:
Thanks Toast, this works better but I need to pull the Certificate info from all the automation accounts (get-azautomationcertificate) from the results. My initial thought was to whittle down the results from Subscriptions -> ResourceGroups -> AutomationAccounts -> AutomationCertificates. If I get to the automationaccounts, then I am back trying to nest another loop for the cert info and I've lost context again. I like Marios idea about keeping everything in the pipeline but I don't think I can stretch it that far.
|
# ? Jul 16, 2021 22:10 |
|
Mario posted:$AAs gets overwritten with each loop over $RGs, so it makes sense that only the last retrieved value is available. Also, building arrays and looping with foreach..in feels awkward in PS rather than using the pipeline. Thanks Mario. I like this idea but I have to start with the resource group collection because my end goal is to get the automation cert info and get-azautomationcertificate requires resourcegroupname.
|
# ? Jul 16, 2021 22:13 |
|
Why are you adding to the list of Resource Groups and looping through the entire list each time?
|
# ? Jul 17, 2021 02:36 |
|
Luna posted:Thanks Mario. I like this idea but I have to start with the resource group collection because my end goal is to get the automation cert info and get-azautomationcertificate requires resourcegroupname. Have you tried piping an AutomationAccount to Get-AzAutomationCertificate? The docs say that AutomationAccount objects have AutomationAccountName and ResourceGroupName properties, and that Get-AzAutomationCertificate's -AutomationAccountName and -ResourceGroupName parameters accept pipeline input by property name.
|
# ? Jul 17, 2021 07:00 |
|
Toast Museum posted:Have you tried piping an AutomationAccount to Get-AzAutomationCertificate? The docs say that AutomationAccount objects have AutomationAccountName and ResourceGroupName properties, and that Get-AzAutomationCertificate's -AutomationAccountName and -ResourceGroupName parameters accept pipeline input by property name. Yea, I piped everything together and threw it in a foreach loop and it worked. Thanks for knocking some sense into me. I'm not a natural coder so I take everything step by step and miss the bigger picture sometimes.
|
# ? Jul 23, 2021 20:51 |
|
FISHMANPET posted:Why are you adding to the list of Resource Groups and looping through the entire list each time? Because I am dumb as a bag of hair.
|
# ? Jul 23, 2021 20:51 |
|
I need powershell help because I am a broke-brain. Basically what I want it to do is take a pre-compiled list of computers, iterate through that list looking for a certain installed program, and when it finds that program open an command prompt on the remote machine and:
I can get it to iterate through the list and find the program installation, however when it comes time to take actions on those machines it just blows through all of the commands way too fast and exits. Or it prompts me for another set of credentials (which it shouldn't) and then fails, and now for some reason it seems to just be crashing or exiting without even looking for the program install. My powershell skills are amateur at best and I honestly can't figure out why this isn't working so any ideas or directions I can go in would be great. Here is the code: code:
|
# ? Oct 7, 2021 20:04 |
|
Do you actually need to involve cmd.exe? It seems simpler to remove items and run the uninstaller/gpupdate from PS directly.
|
# ? Oct 7, 2021 22:22 |
|
For the program I do. The only way it can be uninstalled is by running the setup exe with the /uninstall argument. There is no uninstall key in the registry. It probably would be easier to just call Remove-Item on the directories though.
|
# ? Oct 7, 2021 23:32 |
|
MustardFacial posted:For the program I do. The only way it can be uninstalled is by running the setup exe with the /uninstall argument. There is no uninstall key in the registry. It probably would be easier to just call Remove-Item on the directories though. The question is whether there's anything preventing you from writing your ScriptBlocks like this: code:
Toast Museum fucked around with this message at 01:17 on Oct 8, 2021 |
# ? Oct 8, 2021 01:12 |
|
Sorry for the back-to-back posts, but some other thoughts: I'd use Get-CimInstance within Invoke-Command instead of using Get-WmiObject. That'll reduce the number of remote connections you open by the number of computers with that program. Also, since Get-WmiObject uses a different mechanism than Invoke-Command to reach remote computers, getting rid of it reduces your odds of running into firewall issues and whatnot. You may want to find an alternative to querying Win32_Product quote:Win32_product class isn't query optimized. Queries such as select * from Win32_Product where (name like 'Sniffer%') require WMI to use the MSI provider to enumerate all of the installed products and then parse the full list sequentially to handle the where clause. This process also starts a consistency check of packages installed, verifying, and repairing the install.
|
# ? Oct 8, 2021 01:43 |
|
I am an okay scripter, but I don't do a lot of PowerShell, so I have what are probably some pretty basic questions. I need to add a new DNS server to option 6 in DHCP on all the scopes on a whole mess of servers. I do see the Get- and Set-DHCPServerV4OptionValue cmdlet, but my main questions are: - Can I add a new DNS server, or do I have to just set the value to a new array -- apparently it takes an array, right? -- that includes all of the DNS servers I want? - What if I want to add the new one as the first one in the list, and not the last? - If I have to just get the current list, and create a new array with the new one + the existing ones, how exactly do I do that in PS? I was able to get the list of current ones with code:
Obviously I've removed my test server name and IP address. I am aware after some research that Set-DHCPServerV4OptionValue has an actual -DnsServer argument and I don't have to use OptionID 6, but I don't know if it matters. I don't really know how to build this new array, and my experimenting hasn't worked. Say my current servers are 5.6.7.8 and 9.10.11.12, and I want to add 1.2.3.4 to the beginning of the list. I tried this: code:
I also don't know whether it's correct to put 1.2.3.4 in there as a string! But if I omit the quotes, PS throws an error.
|
# ? Nov 4, 2021 11:49 |
|
guppy posted:I was able to get the list of current ones with Caveat: I haven't used the DhcpServer module specifically. It looks like you may be running into issues because $new ends up containing multiple types, which is probably causing something to choke on it later in the script. As written, this line code:
code:
code:
code:
Re: putting the IP address in quotes, for most cmdlets, that's fine; PowerShell is usually pretty good about implicitly converting types. If you're dealing with a cmdlet or .NET method that specifically needs you to feed it an IPAddress object, you can explicitly cast the string: code:
|
# ? Nov 4, 2021 17:12 |
|
Thanks! That's great, detailed info. I will give this another go.
|
# ? Nov 6, 2021 00:53 |
|
PowerShell 7.2 is out! Microsoft Update support is a nice quality-of-life improvement. The expanded ANSI support and new $PSStyle automatic variable have got me obsessing over my color theme choices.
|
# ? Nov 11, 2021 02:17 |
|
Toast Museum posted:PowerShell 7.2 is out! Also notable that it's built on .NET 6 which also entered GA at the same time I think (Alongside Visual Studio 2022).
|
# ? Nov 11, 2021 17:00 |
|
Pile Of Garbage posted:Also notable that it's built on .NET 6 which also entered GA at the same time I think (Alongside Visual Studio 2022). Yeah, I should have mentioned that. I'm working on a compiled module as a side project, and C# 10's new syntax has been nice to have. Between file-scoped namespaces and global using directives, I find myself writing a lot less boilerplate. Visual Studio 2022's upgraded IntelliSense is pretty nice to have as well, even if it does sometimes make odd choices. I do wish Visual Studio included a PowerShell Module project type, though. Of mostly personal significance, a breaking change introduced in .NET 6 got me started with contributing to the PowerShell repository. After seeing how quickly the issue I reported got resolved, I started looking through the open issues for something to help with. It's the first public repository I've contributed to, and it feels pretty cool to know that a few lines of code that I wrote are slated for PowerShell 7.3.
|
# ? Nov 11, 2021 20:22 |
|
Toast Museum posted:Of mostly personal significance, a breaking change introduced in .NET 6 got me started with contributing to the PowerShell repository. After seeing how quickly the issue I reported got resolved, I started looking through the open issues for something to help with. It's the first public repository I've contributed to, and it feels pretty cool to know that a few lines of code that I wrote are slated for PowerShell 7.3. Nice!
|
# ? Nov 11, 2021 20:35 |
|
|
# ? May 14, 2024 19:17 |
|
Hell, yeah, my dudes. Powershell has been added to SA's bbcode: [code=Powershell]PowerShell code:
|
# ? Nov 16, 2021 04:35 |