powershell

18 Topics
"}},"componentScriptGroups({\"componentId\":\"custom.widget.MicrosoftFooter\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"tagFollowsForNodes({\"nodeIds\":\"board:AppsonAzureBlog\",\"tagText\":\"powershell\"})":[{"__typename":"TagFollowForNodeResponse","coreNode":{"__ref":"Blog:board:AppsonAzureBlog"},"follow":null}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/community/NavbarDropdownToggle\"]})":[{"__ref":"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/OverflowNav\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageView/MessageViewInline\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/Pager/PagerLoadMore\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/Pager/PagerLoadMore-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserLink\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserLink-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageSubject\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageSubject-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageBody\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageBody-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageTime\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageTime-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeIcon\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageUnreadCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageUnreadCount-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageViewCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageViewCount-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/kudos/KudosCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/kudos/KudosCount-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageRepliesCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageRepliesCount-1744658876111"}],"cachedText({\"lastModified\":\"1744658876111\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1744658876111"}]},"CachedAsset:pages-1744410786425":{"__typename":"CachedAsset","id":"pages-1744410786425","value":[{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"BlogViewAllPostsPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId/all-posts/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"CasePortalPage","type":"CASE_PORTAL","urlPath":"/caseportal","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"CreateGroupHubPage","type":"GROUP_HUB","urlPath":"/groups/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"CaseViewPage","type":"CASE_DETAILS","urlPath":"/case/:caseId/:caseNumber","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"InboxPage","type":"COMMUNITY","urlPath":"/inbox","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"HelpFAQPage","type":"COMMUNITY","urlPath":"/help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"IdeaMessagePage","type":"IDEA_POST","urlPath":"/idea/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"IdeaViewAllIdeasPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/all-ideas/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"LoginPage","type":"USER","urlPath":"/signin","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"BlogPostPage","type":"BLOG","urlPath":"/category/:categoryId/blogs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"UserBlogPermissions.Page","type":"COMMUNITY","urlPath":"/c/user-blog-permissions/page","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ThemeEditorPage","type":"COMMUNITY","urlPath":"/designer/themes","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"TkbViewAllArticlesPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId/all-articles/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730142000000,"localOverride":null,"page":{"id":"AllEvents","type":"CUSTOM","urlPath":"/Events","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"OccasionEditPage","type":"EVENT","urlPath":"/event/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"OAuthAuthorizationAllowPage","type":"USER","urlPath":"/auth/authorize/allow","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"PageEditorPage","type":"COMMUNITY","urlPath":"/designer/pages","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"PostPage","type":"COMMUNITY","urlPath":"/category/:categoryId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ForumBoardPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"TkbBoardPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"EventPostPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"UserBadgesPage","type":"COMMUNITY","urlPath":"/users/:login/:userId/badges","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"GroupHubMembershipAction","type":"GROUP_HUB","urlPath":"/membership/join/:nodeId/:membershipType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"MaintenancePage","type":"COMMUNITY","urlPath":"/maintenance","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"IdeaReplyPage","type":"IDEA_REPLY","urlPath":"/idea/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"UserSettingsPage","type":"USER","urlPath":"/mysettings/:userSettingsTab","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"GroupHubsPage","type":"GROUP_HUB","urlPath":"/groups","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ForumPostPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"OccasionRsvpActionPage","type":"OCCASION","urlPath":"/event/:boardId/:messageSubject/:messageId/rsvp/:responseType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"VerifyUserEmailPage","type":"USER","urlPath":"/verifyemail/:userId/:verifyEmailToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"AllOccasionsPage","type":"OCCASION","urlPath":"/category/:categoryId/events/:boardId/all-events/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"EventBoardPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"TkbReplyPage","type":"TKB_REPLY","urlPath":"/kb/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"IdeaBoardPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"CommunityGuideLinesPage","type":"COMMUNITY","urlPath":"/communityguidelines","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"CaseCreatePage","type":"SALESFORCE_CASE_CREATION","urlPath":"/caseportal/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"TkbEditPage","type":"TKB","urlPath":"/kb/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ForgotPasswordPage","type":"USER","urlPath":"/forgotpassword","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"IdeaEditPage","type":"IDEA","urlPath":"/idea/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"TagPage","type":"COMMUNITY","urlPath":"/tag/:tagName","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"BlogBoardPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"OccasionMessagePage","type":"OCCASION_TOPIC","urlPath":"/event/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ManageContentPage","type":"COMMUNITY","urlPath":"/managecontent","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ClosedMembershipNodeNonMembersPage","type":"GROUP_HUB","urlPath":"/closedgroup/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"CommunityPage","type":"COMMUNITY","urlPath":"/","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ForumMessagePage","type":"FORUM_TOPIC","urlPath":"/discussions/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"IdeaPostPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730142000000,"localOverride":null,"page":{"id":"CommunityHub.Page","type":"CUSTOM","urlPath":"/Directory","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"BlogMessagePage","type":"BLOG_ARTICLE","urlPath":"/blog/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"RegistrationPage","type":"USER","urlPath":"/register","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"EditGroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ForumEditPage","type":"FORUM","urlPath":"/discussions/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ResetPasswordPage","type":"USER","urlPath":"/resetpassword/:userId/:resetPasswordToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730142000000,"localOverride":null,"page":{"id":"AllBlogs.Page","type":"CUSTOM","urlPath":"/blogs","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"TkbMessagePage","type":"TKB_ARTICLE","urlPath":"/kb/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"BlogEditPage","type":"BLOG","urlPath":"/blog/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ManageUsersPage","type":"USER","urlPath":"/users/manage/:tab?/:manageUsersTab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ForumReplyPage","type":"FORUM_REPLY","urlPath":"/discussions/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"PrivacyPolicyPage","type":"COMMUNITY","urlPath":"/privacypolicy","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"NotificationPage","type":"COMMUNITY","urlPath":"/notifications","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"UserPage","type":"USER","urlPath":"/users/:login/:userId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"OccasionReplyPage","type":"OCCASION_REPLY","urlPath":"/event/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ManageMembersPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/manage/:tab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"SearchResultsPage","type":"COMMUNITY","urlPath":"/search","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"BlogReplyPage","type":"BLOG_REPLY","urlPath":"/blog/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"GroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"TermsOfServicePage","type":"COMMUNITY","urlPath":"/termsofservice","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"CategoryPage","type":"CATEGORY","urlPath":"/category/:categoryId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"ForumViewAllTopicsPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/all-topics/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"TkbPostPage","type":"TKB","urlPath":"/category/:categoryId/kbs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410786425,"localOverride":null,"page":{"id":"GroupHubPostPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"}],"localOverride":false},"CachedAsset:text:en_US-components/context/AppContext/AppContextProvider-0":{"__typename":"CachedAsset","id":"text:en_US-components/context/AppContext/AppContextProvider-0","value":{"noCommunity":"Cannot find community","noUser":"Cannot find current user","noNode":"Cannot find node with id {nodeId}","noMessage":"Cannot find message with id {messageId}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-0":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-0","value":{"title":"Loading..."},"localOverride":false},"User:user:-1":{"__typename":"User","id":"user:-1","uid":-1,"login":"Deleted","email":"","avatar":null,"rank":null,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":"ANONYMOUS","registrationTime":null,"confirmEmailStatus":false,"registrationAccessLevel":"VIEW","ssoRegistrationFields":[]},"ssoId":null,"profileSettings":{"__typename":"ProfileSettings","dateDisplayStyle":{"__typename":"InheritableStringSettingWithPossibleValues","key":"layout.friendly_dates_enabled","value":"false","localValue":"true","possibleValues":["true","false"]},"dateDisplayFormat":{"__typename":"InheritableStringSetting","key":"layout.format_pattern_date","value":"MMM dd yyyy","localValue":"MM-dd-yyyy"},"language":{"__typename":"InheritableStringSettingWithPossibleValues","key":"profile.language","value":"en-US","localValue":"en","possibleValues":["en-US"]}},"deleted":false},"Theme:customTheme1":{"__typename":"Theme","id":"customTheme1"},"CachedAsset:theme:customTheme1-1744326567586":{"__typename":"CachedAsset","id":"theme:customTheme1-1744326567586","value":{"id":"customTheme1","animation":{"fast":"150ms","normal":"250ms","slow":"500ms","slowest":"750ms","function":"cubic-bezier(0.07, 0.91, 0.51, 1)","__typename":"AnimationThemeSettings"},"avatar":{"borderRadius":"50%","collections":["default"],"__typename":"AvatarThemeSettings"},"basics":{"browserIcon":{"imageAssetName":"favicon-1730836283320.png","imageLastModified":"1730836286415","__typename":"ThemeAsset"},"customerLogo":{"imageAssetName":"favicon-1730836271365.png","imageLastModified":"1730836274203","__typename":"ThemeAsset"},"maximumWidthOfPageContent":"1300px","oneColumnNarrowWidth":"800px","gridGutterWidthMd":"30px","gridGutterWidthXs":"10px","pageWidthStyle":"WIDTH_OF_BROWSER","__typename":"BasicsThemeSettings"},"buttons":{"borderRadiusSm":"3px","borderRadius":"3px","borderRadiusLg":"5px","paddingY":"5px","paddingYLg":"7px","paddingYHero":"var(--lia-bs-btn-padding-y-lg)","paddingX":"12px","paddingXLg":"16px","paddingXHero":"60px","fontStyle":"NORMAL","fontWeight":"700","textTransform":"NONE","disabledOpacity":0.5,"primaryTextColor":"var(--lia-bs-white)","primaryTextHoverColor":"var(--lia-bs-white)","primaryTextActiveColor":"var(--lia-bs-white)","primaryBgColor":"var(--lia-bs-primary)","primaryBgHoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.85))","primaryBgActiveColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.7))","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","primaryBorderActive":"1px solid transparent","primaryBorderFocus":"1px solid var(--lia-bs-white)","primaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","secondaryTextColor":"var(--lia-bs-gray-900)","secondaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","secondaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","secondaryBgColor":"var(--lia-bs-gray-200)","secondaryBgHoverColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.96))","secondaryBgActiveColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.92))","secondaryBorder":"1px solid transparent","secondaryBorderHover":"1px solid transparent","secondaryBorderActive":"1px solid transparent","secondaryBorderFocus":"1px solid transparent","secondaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","tertiaryTextColor":"var(--lia-bs-gray-900)","tertiaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","tertiaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","tertiaryBgColor":"transparent","tertiaryBgHoverColor":"transparent","tertiaryBgActiveColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.04)","tertiaryBorder":"1px solid transparent","tertiaryBorderHover":"1px solid hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","tertiaryBorderActive":"1px solid transparent","tertiaryBorderFocus":"1px solid transparent","tertiaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","destructiveTextColor":"var(--lia-bs-danger)","destructiveTextHoverColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.95))","destructiveTextActiveColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.9))","destructiveBgColor":"var(--lia-bs-gray-200)","destructiveBgHoverColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.96))","destructiveBgActiveColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.92))","destructiveBorder":"1px solid transparent","destructiveBorderHover":"1px solid transparent","destructiveBorderActive":"1px solid transparent","destructiveBorderFocus":"1px solid transparent","destructiveBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","__typename":"ButtonsThemeSettings"},"border":{"color":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","mainContent":"NONE","sideContent":"LIGHT","radiusSm":"3px","radius":"5px","radiusLg":"9px","radius50":"100vw","__typename":"BorderThemeSettings"},"boxShadow":{"xs":"0 0 0 1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08), 0 3px 0 -1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.16)","sm":"0 2px 4px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.12)","md":"0 5px 15px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.3)","lg":"0 10px 30px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.3)","__typename":"BoxShadowThemeSettings"},"cards":{"bgColor":"var(--lia-panel-bg-color)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":"var(--lia-box-shadow-xs)","__typename":"CardsThemeSettings"},"chip":{"maxWidth":"300px","height":"30px","__typename":"ChipThemeSettings"},"coreTypes":{"defaultMessageLinkColor":"var(--lia-bs-link-color)","defaultMessageLinkDecoration":"none","defaultMessageLinkFontStyle":"NORMAL","defaultMessageLinkFontWeight":"400","defaultMessageFontStyle":"NORMAL","defaultMessageFontWeight":"400","forumColor":"#4099E2","forumFontFamily":"var(--lia-bs-font-family-base)","forumFontWeight":"var(--lia-default-message-font-weight)","forumLineHeight":"var(--lia-bs-line-height-base)","forumFontStyle":"var(--lia-default-message-font-style)","forumMessageLinkColor":"var(--lia-default-message-link-color)","forumMessageLinkDecoration":"var(--lia-default-message-link-decoration)","forumMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","forumMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","forumSolvedColor":"#148563","blogColor":"#1CBAA0","blogFontFamily":"var(--lia-bs-font-family-base)","blogFontWeight":"var(--lia-default-message-font-weight)","blogLineHeight":"1.75","blogFontStyle":"var(--lia-default-message-font-style)","blogMessageLinkColor":"var(--lia-default-message-link-color)","blogMessageLinkDecoration":"var(--lia-default-message-link-decoration)","blogMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","blogMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","tkbColor":"#4C6B90","tkbFontFamily":"var(--lia-bs-font-family-base)","tkbFontWeight":"var(--lia-default-message-font-weight)","tkbLineHeight":"1.75","tkbFontStyle":"var(--lia-default-message-font-style)","tkbMessageLinkColor":"var(--lia-default-message-link-color)","tkbMessageLinkDecoration":"var(--lia-default-message-link-decoration)","tkbMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","tkbMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaColor":"#4099E2","qandaFontFamily":"var(--lia-bs-font-family-base)","qandaFontWeight":"var(--lia-default-message-font-weight)","qandaLineHeight":"var(--lia-bs-line-height-base)","qandaFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkColor":"var(--lia-default-message-link-color)","qandaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","qandaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaSolvedColor":"#3FA023","ideaColor":"#FF8000","ideaFontFamily":"var(--lia-bs-font-family-base)","ideaFontWeight":"var(--lia-default-message-font-weight)","ideaLineHeight":"var(--lia-bs-line-height-base)","ideaFontStyle":"var(--lia-default-message-font-style)","ideaMessageLinkColor":"var(--lia-default-message-link-color)","ideaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","ideaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","ideaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","contestColor":"#FCC845","contestFontFamily":"var(--lia-bs-font-family-base)","contestFontWeight":"var(--lia-default-message-font-weight)","contestLineHeight":"var(--lia-bs-line-height-base)","contestFontStyle":"var(--lia-default-message-link-font-style)","contestMessageLinkColor":"var(--lia-default-message-link-color)","contestMessageLinkDecoration":"var(--lia-default-message-link-decoration)","contestMessageLinkFontStyle":"ITALIC","contestMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","occasionColor":"#D13A1F","occasionFontFamily":"var(--lia-bs-font-family-base)","occasionFontWeight":"var(--lia-default-message-font-weight)","occasionLineHeight":"var(--lia-bs-line-height-base)","occasionFontStyle":"var(--lia-default-message-font-style)","occasionMessageLinkColor":"var(--lia-default-message-link-color)","occasionMessageLinkDecoration":"var(--lia-default-message-link-decoration)","occasionMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","occasionMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","grouphubColor":"#333333","categoryColor":"#949494","communityColor":"#FFFFFF","productColor":"#949494","__typename":"CoreTypesThemeSettings"},"colors":{"black":"#000000","white":"#FFFFFF","gray100":"#F7F7F7","gray200":"#F7F7F7","gray300":"#E8E8E8","gray400":"#D9D9D9","gray500":"#CCCCCC","gray600":"#717171","gray700":"#707070","gray800":"#545454","gray900":"#333333","dark":"#545454","light":"#F7F7F7","primary":"#0069D4","secondary":"#333333","bodyText":"#1E1E1E","bodyBg":"#FFFFFF","info":"#409AE2","success":"#41C5AE","warning":"#FCC844","danger":"#BC341B","alertSystem":"#FF6600","textMuted":"#707070","highlight":"#FFFCAD","outline":"var(--lia-bs-primary)","custom":["#D3F5A4","#243A5E"],"__typename":"ColorsThemeSettings"},"divider":{"size":"3px","marginLeft":"4px","marginRight":"4px","borderRadius":"50%","bgColor":"var(--lia-bs-gray-600)","bgColorActive":"var(--lia-bs-gray-600)","__typename":"DividerThemeSettings"},"dropdown":{"fontSize":"var(--lia-bs-font-size-sm)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius-sm)","dividerBg":"var(--lia-bs-gray-300)","itemPaddingY":"5px","itemPaddingX":"20px","headerColor":"var(--lia-bs-gray-700)","__typename":"DropdownThemeSettings"},"email":{"link":{"color":"#0069D4","hoverColor":"#0061c2","decoration":"none","hoverDecoration":"underline","__typename":"EmailLinkSettings"},"border":{"color":"#e4e4e4","__typename":"EmailBorderSettings"},"buttons":{"borderRadiusLg":"5px","paddingXLg":"16px","paddingYLg":"7px","fontWeight":"700","primaryTextColor":"#ffffff","primaryTextHoverColor":"#ffffff","primaryBgColor":"#0069D4","primaryBgHoverColor":"#005cb8","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","__typename":"EmailButtonsSettings"},"panel":{"borderRadius":"5px","borderColor":"#e4e4e4","__typename":"EmailPanelSettings"},"__typename":"EmailThemeSettings"},"emoji":{"skinToneDefault":"#ffcd43","skinToneLight":"#fae3c5","skinToneMediumLight":"#e2cfa5","skinToneMedium":"#daa478","skinToneMediumDark":"#a78058","skinToneDark":"#5e4d43","__typename":"EmojiThemeSettings"},"heading":{"color":"var(--lia-bs-body-color)","fontFamily":"Segoe UI","fontStyle":"NORMAL","fontWeight":"400","h1FontSize":"34px","h2FontSize":"32px","h3FontSize":"28px","h4FontSize":"24px","h5FontSize":"20px","h6FontSize":"16px","lineHeight":"1.3","subHeaderFontSize":"11px","subHeaderFontWeight":"500","h1LetterSpacing":"normal","h2LetterSpacing":"normal","h3LetterSpacing":"normal","h4LetterSpacing":"normal","h5LetterSpacing":"normal","h6LetterSpacing":"normal","subHeaderLetterSpacing":"2px","h1FontWeight":"var(--lia-bs-headings-font-weight)","h2FontWeight":"var(--lia-bs-headings-font-weight)","h3FontWeight":"var(--lia-bs-headings-font-weight)","h4FontWeight":"var(--lia-bs-headings-font-weight)","h5FontWeight":"var(--lia-bs-headings-font-weight)","h6FontWeight":"var(--lia-bs-headings-font-weight)","__typename":"HeadingThemeSettings"},"icons":{"size10":"10px","size12":"12px","size14":"14px","size16":"16px","size20":"20px","size24":"24px","size30":"30px","size40":"40px","size50":"50px","size60":"60px","size80":"80px","size120":"120px","size160":"160px","__typename":"IconsThemeSettings"},"imagePreview":{"bgColor":"var(--lia-bs-gray-900)","titleColor":"var(--lia-bs-white)","controlColor":"var(--lia-bs-white)","controlBgColor":"var(--lia-bs-gray-800)","__typename":"ImagePreviewThemeSettings"},"input":{"borderColor":"var(--lia-bs-gray-600)","disabledColor":"var(--lia-bs-gray-600)","focusBorderColor":"var(--lia-bs-primary)","labelMarginBottom":"10px","btnFontSize":"var(--lia-bs-font-size-sm)","focusBoxShadow":"0 0 0 3px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","checkLabelMarginBottom":"2px","checkboxBorderRadius":"3px","borderRadiusSm":"var(--lia-bs-border-radius-sm)","borderRadius":"var(--lia-bs-border-radius)","borderRadiusLg":"var(--lia-bs-border-radius-lg)","formTextMarginTop":"4px","textAreaBorderRadius":"var(--lia-bs-border-radius)","activeFillColor":"var(--lia-bs-primary)","__typename":"InputThemeSettings"},"loading":{"dotDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.2)","dotLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.5)","barDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.06)","barLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.4)","__typename":"LoadingThemeSettings"},"link":{"color":"var(--lia-bs-primary)","hoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) - 10%))","decoration":"none","hoverDecoration":"underline","__typename":"LinkThemeSettings"},"listGroup":{"itemPaddingY":"15px","itemPaddingX":"15px","borderColor":"var(--lia-bs-gray-300)","__typename":"ListGroupThemeSettings"},"modal":{"contentTextColor":"var(--lia-bs-body-color)","contentBg":"var(--lia-bs-white)","backgroundBg":"var(--lia-bs-black)","smSize":"440px","mdSize":"760px","lgSize":"1080px","backdropOpacity":0.3,"contentBoxShadowXs":"var(--lia-bs-box-shadow-sm)","contentBoxShadow":"var(--lia-bs-box-shadow)","headerFontWeight":"700","__typename":"ModalThemeSettings"},"navbar":{"position":"FIXED","background":{"attachment":null,"clip":null,"color":"var(--lia-bs-white)","imageAssetName":"","imageLastModified":"0","origin":null,"position":"CENTER_CENTER","repeat":"NO_REPEAT","size":"COVER","__typename":"BackgroundProps"},"backgroundOpacity":0.8,"paddingTop":"15px","paddingBottom":"15px","borderBottom":"1px solid var(--lia-bs-border-color)","boxShadow":"var(--lia-bs-box-shadow-sm)","brandMarginRight":"30px","brandMarginRightSm":"10px","brandLogoHeight":"30px","linkGap":"10px","linkJustifyContent":"flex-start","linkPaddingY":"5px","linkPaddingX":"10px","linkDropdownPaddingY":"9px","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkColor":"var(--lia-bs-body-color)","linkHoverColor":"var(--lia-bs-primary)","linkFontSize":"var(--lia-bs-font-size-sm)","linkFontStyle":"NORMAL","linkFontWeight":"400","linkTextTransform":"NONE","linkLetterSpacing":"normal","linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkBgColor":"transparent","linkBgHoverColor":"transparent","linkBorder":"none","linkBorderHover":"none","linkBoxShadow":"none","linkBoxShadowHover":"none","linkTextBorderBottom":"none","linkTextBorderBottomHover":"none","dropdownPaddingTop":"10px","dropdownPaddingBottom":"15px","dropdownPaddingX":"10px","dropdownMenuOffset":"2px","dropdownDividerMarginTop":"10px","dropdownDividerMarginBottom":"10px","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","controllerIconColor":"var(--lia-bs-body-color)","controllerIconHoverColor":"var(--lia-bs-body-color)","controllerTextColor":"var(--lia-nav-controller-icon-color)","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","controllerHighlightColor":"hsla(30, 100%, 50%)","controllerHighlightTextColor":"var(--lia-yiq-light)","controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerColor":"var(--lia-nav-controller-icon-color)","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","hamburgerBgColor":"transparent","hamburgerBgHoverColor":"transparent","hamburgerBorder":"none","hamburgerBorderHover":"none","collapseMenuMarginLeft":"20px","collapseMenuDividerBg":"var(--lia-nav-link-color)","collapseMenuDividerOpacity":0.16,"__typename":"NavbarThemeSettings"},"pager":{"textColor":"var(--lia-bs-link-color)","textFontWeight":"var(--lia-font-weight-md)","textFontSize":"var(--lia-bs-font-size-sm)","__typename":"PagerThemeSettings"},"panel":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-bs-border-radius)","borderColor":"var(--lia-bs-border-color)","boxShadow":"none","__typename":"PanelThemeSettings"},"popover":{"arrowHeight":"8px","arrowWidth":"16px","maxWidth":"300px","minWidth":"100px","headerBg":"var(--lia-bs-white)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius)","boxShadow":"0 0.5rem 1rem hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.15)","__typename":"PopoverThemeSettings"},"prism":{"color":"#000000","bgColor":"#f5f2f0","fontFamily":"var(--font-family-monospace)","fontSize":"var(--lia-bs-font-size-base)","fontWeightBold":"var(--lia-bs-font-weight-bold)","fontStyleItalic":"italic","tabSize":2,"highlightColor":"#b3d4fc","commentColor":"#62707e","punctuationColor":"#6f6f6f","namespaceOpacity":"0.7","propColor":"#990055","selectorColor":"#517a00","operatorColor":"#906736","operatorBgColor":"hsla(0, 0%, 100%, 0.5)","keywordColor":"#0076a9","functionColor":"#d3284b","variableColor":"#c14700","__typename":"PrismThemeSettings"},"rte":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":" var(--lia-panel-box-shadow)","customColor1":"#bfedd2","customColor2":"#fbeeb8","customColor3":"#f8cac6","customColor4":"#eccafa","customColor5":"#c2e0f4","customColor6":"#2dc26b","customColor7":"#f1c40f","customColor8":"#e03e2d","customColor9":"#b96ad9","customColor10":"#3598db","customColor11":"#169179","customColor12":"#e67e23","customColor13":"#ba372a","customColor14":"#843fa1","customColor15":"#236fa1","customColor16":"#ecf0f1","customColor17":"#ced4d9","customColor18":"#95a5a6","customColor19":"#7e8c8d","customColor20":"#34495e","customColor21":"#000000","customColor22":"#ffffff","defaultMessageHeaderMarginTop":"40px","defaultMessageHeaderMarginBottom":"20px","defaultMessageItemMarginTop":"0","defaultMessageItemMarginBottom":"10px","diffAddedColor":"hsla(170, 53%, 51%, 0.4)","diffChangedColor":"hsla(43, 97%, 63%, 0.4)","diffNoneColor":"hsla(0, 0%, 80%, 0.4)","diffRemovedColor":"hsla(9, 74%, 47%, 0.4)","specialMessageHeaderMarginTop":"40px","specialMessageHeaderMarginBottom":"20px","specialMessageItemMarginTop":"0","specialMessageItemMarginBottom":"10px","__typename":"RteThemeSettings"},"tags":{"bgColor":"var(--lia-bs-gray-200)","bgHoverColor":"var(--lia-bs-gray-400)","borderRadius":"var(--lia-bs-border-radius-sm)","color":"var(--lia-bs-body-color)","hoverColor":"var(--lia-bs-body-color)","fontWeight":"var(--lia-font-weight-md)","fontSize":"var(--lia-font-size-xxs)","textTransform":"UPPERCASE","letterSpacing":"0.5px","__typename":"TagsThemeSettings"},"toasts":{"borderRadius":"var(--lia-bs-border-radius)","paddingX":"12px","__typename":"ToastsThemeSettings"},"typography":{"fontFamilyBase":"Segoe UI","fontStyleBase":"NORMAL","fontWeightBase":"400","fontWeightLight":"300","fontWeightNormal":"400","fontWeightMd":"500","fontWeightBold":"700","letterSpacingSm":"normal","letterSpacingXs":"normal","lineHeightBase":"1.5","fontSizeBase":"16px","fontSizeXxs":"11px","fontSizeXs":"12px","fontSizeSm":"14px","fontSizeLg":"20px","fontSizeXl":"24px","smallFontSize":"14px","customFonts":[{"source":"SERVER","name":"Segoe UI","styles":[{"style":"NORMAL","weight":"400","__typename":"FontStyleData"},{"style":"NORMAL","weight":"300","__typename":"FontStyleData"},{"style":"NORMAL","weight":"600","__typename":"FontStyleData"},{"style":"NORMAL","weight":"700","__typename":"FontStyleData"},{"style":"ITALIC","weight":"400","__typename":"FontStyleData"}],"assetNames":["SegoeUI-normal-400.woff2","SegoeUI-normal-300.woff2","SegoeUI-normal-600.woff2","SegoeUI-normal-700.woff2","SegoeUI-italic-400.woff2"],"__typename":"CustomFont"},{"source":"SERVER","name":"MWF Fluent Icons","styles":[{"style":"NORMAL","weight":"400","__typename":"FontStyleData"}],"assetNames":["MWFFluentIcons-normal-400.woff2"],"__typename":"CustomFont"}],"__typename":"TypographyThemeSettings"},"unstyledListItem":{"marginBottomSm":"5px","marginBottomMd":"10px","marginBottomLg":"15px","marginBottomXl":"20px","marginBottomXxl":"25px","__typename":"UnstyledListItemThemeSettings"},"yiq":{"light":"#ffffff","dark":"#000000","__typename":"YiqThemeSettings"},"colorLightness":{"primaryDark":0.36,"primaryLight":0.74,"primaryLighter":0.89,"primaryLightest":0.95,"infoDark":0.39,"infoLight":0.72,"infoLighter":0.85,"infoLightest":0.93,"successDark":0.24,"successLight":0.62,"successLighter":0.8,"successLightest":0.91,"warningDark":0.39,"warningLight":0.68,"warningLighter":0.84,"warningLightest":0.93,"dangerDark":0.41,"dangerLight":0.72,"dangerLighter":0.89,"dangerLightest":0.95,"__typename":"ColorLightnessThemeSettings"},"localOverride":false,"__typename":"Theme"},"localOverride":false},"CachedAsset:text:en_US-components/common/EmailVerification-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/common/EmailVerification-1744658876111","value":{"email.verification.title":"Email Verification Required","email.verification.message.update.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. To change your email, visit My Settings.","email.verification.message.resend.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. Resend email."},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-1744658876111","value":{"title":"Loading..."},"localOverride":false},"CachedAsset:text:en_US-pages/tags/TagPage-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-pages/tags/TagPage-1744658876111","value":{"tagPageTitle":"Tag:\"{tagName}\" | {communityTitle}","tagPageForNodeTitle":"Tag:\"{tagName}\" in \"{title}\" | {communityTitle}","name":"Tags Page","tag":"Tag: {tagName}"},"localOverride":false},"Category:category:Azure":{"__typename":"Category","id":"category:Azure","entityType":"CATEGORY","displayId":"Azure","nodeType":"category","depth":3,"title":"Azure","shortTitle":"Azure","parent":{"__ref":"Category:category:products-services"},"categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:top":{"__typename":"Category","id":"category:top","displayId":"top","nodeType":"category","depth":0,"title":"Top"},"Category:category:communities":{"__typename":"Category","id":"category:communities","displayId":"communities","nodeType":"category","depth":1,"parent":{"__ref":"Category:category:top"},"title":"Communities"},"Category:category:products-services":{"__typename":"Category","id":"category:products-services","displayId":"products-services","nodeType":"category","depth":2,"parent":{"__ref":"Category:category:communities"},"title":"Products"},"Blog:board:AppsonAzureBlog":{"__typename":"Blog","id":"board:AppsonAzureBlog","entityType":"BLOG","displayId":"AppsonAzureBlog","nodeType":"board","depth":4,"conversationStyle":"BLOG","title":"Apps on Azure Blog","description":"","avatar":null,"profileSettings":{"__typename":"ProfileSettings","language":null},"parent":{"__ref":"Category:category:Azure"},"ancestors":{"__typename":"CoreNodeConnection","edges":[{"__typename":"CoreNodeEdge","node":{"__ref":"Community:community:gxcuf89792"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:communities"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:products-services"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:Azure"}}]},"userContext":{"__typename":"NodeUserContext","canAddAttachments":false,"canUpdateNode":false,"canPostMessages":false,"isSubscribed":false},"boardPolicies":{"__typename":"BoardPolicies","canPublishArticleOnCreate":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","key":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","args":[]}}},"shortTitle":"Apps on Azure Blog","tagPolicies":{"__typename":"TagPolicies","canSubscribeTagOnNode":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.labels.action.corenode.subscribe_labels.allow.accessDenied","key":"error.lithium.policies.labels.action.corenode.subscribe_labels.allow.accessDenied","args":[]}},"canManageTagDashboard":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.labels.action.corenode.admin_labels.allow.accessDenied","key":"error.lithium.policies.labels.action.corenode.admin_labels.allow.accessDenied","args":[]}}}},"CachedAsset:quilt:o365.prod:pages/tags/TagPage:board:AppsonAzureBlog-1744984043881":{"__typename":"CachedAsset","id":"quilt:o365.prod:pages/tags/TagPage:board:AppsonAzureBlog-1744984043881","value":{"id":"TagPage","container":{"id":"Common","headerProps":{"removeComponents":["community.widget.bannerWidget"],"__typename":"QuiltContainerSectionProps"},"items":[{"id":"tag-header-widget","layout":"ONE_COLUMN","bgColor":"var(--lia-bs-white)","showBorder":"BOTTOM","sectionEditLevel":"LOCKED","columnMap":{"main":[{"id":"tags.widget.TagsHeaderWidget","__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"},"__typename":"OneColumnQuiltSection"},{"id":"messages-list-for-tag-widget","layout":"ONE_COLUMN","columnMap":{"main":[{"id":"messages.widget.messageListForNodeByRecentActivityWidget","props":{"viewVariant":{"type":"inline","props":{"useUnreadCount":true,"useViewCount":true,"useAuthorLogin":true,"clampBodyLines":3,"useAvatar":true,"useBoardIcon":false,"useKudosCount":true,"usePreviewMedia":true,"useTags":false,"useNode":true,"useNodeLink":true,"useTextBody":true,"truncateBodyLength":-1,"useBody":true,"useRepliesCount":true,"useSolvedBadge":true,"timeStampType":"conversation.lastPostingActivityTime","useMessageTimeLink":true,"clampSubjectLines":2}},"panelType":"divider","useTitle":false,"hideIfEmpty":false,"pagerVariant":{"type":"loadMore"},"style":"list","showTabs":true,"tabItemMap":{"default":{"mostRecent":true,"mostRecentUserContent":false,"newest":false},"additional":{"mostKudoed":true,"mostViewed":true,"mostReplies":false,"noReplies":false,"noSolutions":false,"solutions":false}}},"__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"},"__typename":"OneColumnQuiltSection"}],"__typename":"QuiltContainer"},"__typename":"Quilt"},"localOverride":false},"CachedAsset:quiltWrapper:o365.prod:Common:1744410784159":{"__typename":"CachedAsset","id":"quiltWrapper:o365.prod:Common:1744410784159","value":{"id":"Common","header":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"community.widget.navbarWidget","props":{"showUserName":true,"showRegisterLink":true,"useIconLanguagePicker":true,"useLabelLanguagePicker":true,"className":"QuiltComponent_lia-component-edit-mode__0nCcm","links":{"sideLinks":[],"mainLinks":[{"children":[],"linkType":"INTERNAL","id":"gxcuf89792","params":{},"routeName":"CommunityPage"},{"children":[],"linkType":"EXTERNAL","id":"external-link","url":"/Directory","target":"SELF"},{"children":[{"linkType":"INTERNAL","id":"microsoft365","params":{"categoryId":"microsoft365"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-teams","params":{"categoryId":"MicrosoftTeams"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"windows","params":{"categoryId":"Windows"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-securityand-compliance","params":{"categoryId":"microsoft-security"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"outlook","params":{"categoryId":"Outlook"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"planner","params":{"categoryId":"Planner"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"windows-server","params":{"categoryId":"Windows-Server"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"azure","params":{"categoryId":"Azure"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"exchange","params":{"categoryId":"Exchange"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-endpoint-manager","params":{"categoryId":"microsoft-endpoint-manager"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"s-q-l-server","params":{"categoryId":"SQL-Server"},"routeName":"CategoryPage"},{"linkType":"EXTERNAL","id":"external-link-2","url":"/Directory","target":"SELF"}],"linkType":"EXTERNAL","id":"communities","url":"/","target":"BLANK"},{"children":[{"linkType":"INTERNAL","id":"education-sector","params":{"categoryId":"EducationSector"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"a-i","params":{"categoryId":"AI"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"i-t-ops-talk","params":{"categoryId":"ITOpsTalk"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"partner-community","params":{"categoryId":"PartnerCommunity"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-mechanics","params":{"categoryId":"MicrosoftMechanics"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"healthcare-and-life-sciences","params":{"categoryId":"HealthcareAndLifeSciences"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"public-sector","params":{"categoryId":"PublicSector"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"io-t","params":{"categoryId":"IoT"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"driving-adoption","params":{"categoryId":"DrivingAdoption"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"s-m-b","params":{"categoryId":"SMB"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"startupsat-microsoft","params":{"categoryId":"StartupsatMicrosoft"},"routeName":"CategoryPage"},{"linkType":"EXTERNAL","id":"external-link-1","url":"/Directory","target":"SELF"}],"linkType":"EXTERNAL","id":"communities-1","url":"/","target":"SELF"},{"children":[],"linkType":"EXTERNAL","id":"external","url":"/Blogs","target":"SELF"},{"children":[],"linkType":"EXTERNAL","id":"external-1","url":"/Events","target":"SELF"},{"children":[{"linkType":"INTERNAL","id":"microsoft-learn-1","params":{"categoryId":"MicrosoftLearn"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-learn-blog","params":{"boardId":"MicrosoftLearnBlog","categoryId":"MicrosoftLearn"},"routeName":"BlogBoardPage"},{"linkType":"EXTERNAL","id":"external-10","url":"https://learningroomdirectory.microsoft.com/","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-3","url":"https://docs.microsoft.com/learn/dynamics365/?WT.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-4","url":"https://docs.microsoft.com/learn/m365/?wt.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-5","url":"https://docs.microsoft.com/learn/topics/sci/?wt.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-6","url":"https://docs.microsoft.com/learn/powerplatform/?wt.mc_id=techcom_header-webpage-powerplatform","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-7","url":"https://docs.microsoft.com/learn/github/?wt.mc_id=techcom_header-webpage-github","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-8","url":"https://docs.microsoft.com/learn/teams/?wt.mc_id=techcom_header-webpage-teams","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-9","url":"https://docs.microsoft.com/learn/dotnet/?wt.mc_id=techcom_header-webpage-dotnet","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-2","url":"https://docs.microsoft.com/learn/azure/?WT.mc_id=techcom_header-webpage-m365","target":"BLANK"}],"linkType":"INTERNAL","id":"microsoft-learn","params":{"categoryId":"MicrosoftLearn"},"routeName":"CategoryPage"},{"children":[],"linkType":"INTERNAL","id":"community-info-center","params":{"categoryId":"Community-Info-Center"},"routeName":"CategoryPage"}]},"style":{"boxShadow":"var(--lia-bs-box-shadow-sm)","controllerHighlightColor":"hsla(30, 100%, 50%)","linkFontWeight":"400","dropdownDividerMarginBottom":"10px","hamburgerBorderHover":"none","linkBoxShadowHover":"none","linkFontSize":"14px","backgroundOpacity":0.8,"controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerBgColor":"transparent","hamburgerColor":"var(--lia-nav-controller-icon-color)","linkTextBorderBottom":"none","brandLogoHeight":"30px","linkBgHoverColor":"transparent","linkLetterSpacing":"normal","collapseMenuDividerOpacity":0.16,"dropdownPaddingBottom":"15px","paddingBottom":"15px","dropdownMenuOffset":"2px","hamburgerBgHoverColor":"transparent","borderBottom":"1px solid var(--lia-bs-border-color)","hamburgerBorder":"none","dropdownPaddingX":"10px","brandMarginRightSm":"10px","linkBoxShadow":"none","collapseMenuDividerBg":"var(--lia-nav-link-color)","linkColor":"var(--lia-bs-body-color)","linkJustifyContent":"flex-start","dropdownPaddingTop":"10px","controllerHighlightTextColor":"var(--lia-yiq-dark)","controllerTextColor":"var(--lia-nav-controller-icon-color)","background":{"imageAssetName":"","color":"var(--lia-bs-white)","size":"COVER","repeat":"NO_REPEAT","position":"CENTER_CENTER","imageLastModified":""},"linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkHoverColor":"var(--lia-bs-body-color)","position":"FIXED","linkBorder":"none","linkTextBorderBottomHover":"2px solid var(--lia-bs-body-color)","brandMarginRight":"30px","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","linkBorderHover":"none","collapseMenuMarginLeft":"20px","linkFontStyle":"NORMAL","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","linkPaddingX":"10px","linkPaddingY":"5px","paddingTop":"15px","linkTextTransform":"NONE","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","linkBgColor":"transparent","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkDropdownPaddingY":"9px","controllerIconColor":"var(--lia-bs-body-color)","dropdownDividerMarginTop":"10px","linkGap":"10px","controllerIconHoverColor":"var(--lia-bs-body-color)"},"showSearchIcon":false,"languagePickerStyle":"iconAndLabel"},"__typename":"QuiltComponent"},{"id":"community.widget.breadcrumbWidget","props":{"backgroundColor":"transparent","linkHighlightColor":"var(--lia-bs-primary)","visualEffects":{"showBottomBorder":true},"linkTextColor":"var(--lia-bs-gray-700)"},"__typename":"QuiltComponent"},{"id":"custom.widget.community_banner","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"usePageWidth":false,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.HeroBanner","props":{"widgetVisibility":"signedInOrAnonymous","usePageWidth":false,"useTitle":true,"cMax_items":3,"useBackground":false,"title":"","lazyLoad":false,"widgetChooser":"custom.widget.HeroBanner"},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"footer":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"custom.widget.MicrosoftFooter","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"__typename":"QuiltWrapper","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-components/common/ActionFeedback-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/common/ActionFeedback-1744658876111","value":{"joinedGroupHub.title":"Welcome","joinedGroupHub.message":"You are now a member of this group and are subscribed to updates.","groupHubInviteNotFound.title":"Invitation Not Found","groupHubInviteNotFound.message":"Sorry, we could not find your invitation to the group. The owner may have canceled the invite.","groupHubNotFound.title":"Group Not Found","groupHubNotFound.message":"The grouphub you tried to join does not exist. It may have been deleted.","existingGroupHubMember.title":"Already Joined","existingGroupHubMember.message":"You are already a member of this group.","accountLocked.title":"Account Locked","accountLocked.message":"Your account has been locked due to multiple failed attempts. Try again in {lockoutTime} minutes.","editedGroupHub.title":"Changes Saved","editedGroupHub.message":"Your group has been updated.","leftGroupHub.title":"Goodbye","leftGroupHub.message":"You are no longer a member of this group and will not receive future updates.","deletedGroupHub.title":"Deleted","deletedGroupHub.message":"The group has been deleted.","groupHubCreated.title":"Group Created","groupHubCreated.message":"{groupHubName} is ready to use","accountClosed.title":"Account Closed","accountClosed.message":"The account has been closed and you will now be redirected to the homepage","resetTokenExpired.title":"Reset Password Link has Expired","resetTokenExpired.message":"Try resetting your password again","invalidUrl.title":"Invalid URL","invalidUrl.message":"The URL you're using is not recognized. Verify your URL and try again.","accountClosedForUser.title":"Account Closed","accountClosedForUser.message":"{userName}'s account is closed","inviteTokenInvalid.title":"Invitation Invalid","inviteTokenInvalid.message":"Your invitation to the community has been canceled or expired.","inviteTokenError.title":"Invitation Verification Failed","inviteTokenError.message":"The url you are utilizing is not recognized. Verify your URL and try again","pageNotFound.title":"Access Denied","pageNotFound.message":"You do not have access to this area of the community or it doesn't exist","eventAttending.title":"Responded as Attending","eventAttending.message":"You'll be notified when there's new activity and reminded as the event approaches","eventInterested.title":"Responded as Interested","eventInterested.message":"You'll be notified when there's new activity and reminded as the event approaches","eventNotFound.title":"Event Not Found","eventNotFound.message":"The event you tried to respond to does not exist.","redirectToRelatedPage.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.message":"The content you are trying to access is archived","redirectToRelatedPage.message":"The content you are trying to access is archived","relatedUrl.archivalLink.flyoutMessage":"The content you are trying to access is archived View Archived Content"},"localOverride":false},"CachedAsset:component:custom.widget.community_banner-en-1744400827777":{"__typename":"CachedAsset","id":"component:custom.widget.community_banner-en-1744400827777","value":{"component":{"id":"custom.widget.community_banner","template":{"id":"community_banner","markupLanguage":"HANDLEBARS","style":".community-banner {\n a.top-bar.btn {\n top: 0px;\n width: 100%;\n z-index: 999;\n text-align: center;\n left: 0px;\n background: #0068b8;\n color: white;\n padding: 10px 0px;\n display: block;\n box-shadow: none !important;\n border: none !important;\n border-radius: none !important;\n margin: 0px !important;\n font-size: 14px;\n }\n}\n","texts":null,"defaults":{"config":{"applicablePages":[],"description":"community announcement text","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.community_banner","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"community announcement text","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":{"css":".custom_widget_community_banner_community-banner_1x9u2_1 {\n a.custom_widget_community_banner_top-bar_1x9u2_2.custom_widget_community_banner_btn_1x9u2_2 {\n top: 0;\n width: 100%;\n z-index: 999;\n text-align: center;\n left: 0;\n background: #0068b8;\n color: white;\n padding: 0.625rem 0;\n display: block;\n box-shadow: none !important;\n border: none !important;\n border-radius: none !important;\n margin: 0 !important;\n font-size: 0.875rem;\n }\n}\n","tokens":{"community-banner":"custom_widget_community_banner_community-banner_1x9u2_1","top-bar":"custom_widget_community_banner_top-bar_1x9u2_2","btn":"custom_widget_community_banner_btn_1x9u2_2"}},"form":null},"localOverride":false},"CachedAsset:component:custom.widget.HeroBanner-en-1744400827777":{"__typename":"CachedAsset","id":"component:custom.widget.HeroBanner-en-1744400827777","value":{"component":{"id":"custom.widget.HeroBanner","template":{"id":"HeroBanner","markupLanguage":"REACT","style":null,"texts":{"searchPlaceholderText":"Search this community","followActionText":"Follow","unfollowActionText":"Following","searchOnHoverText":"Please enter your search term(s) and then press return key to complete a search.","blogs.sidebar.pagetitle":"Latest Blogs | Microsoft Tech Community","followThisNode":"Follow this node","unfollowThisNode":"Unfollow this node"},"defaults":{"config":{"applicablePages":[],"description":null,"fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[{"id":"max_items","dataType":"NUMBER","list":false,"defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"control":"INPUT","__typename":"PropDefinition"}],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.HeroBanner","form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"},"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":null,"fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[{"id":"max_items","dataType":"NUMBER","list":false,"defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"control":"INPUT","__typename":"PropDefinition"}],"__typename":"ComponentProperties"},"form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"},"__typename":"Component","localOverride":false},"globalCss":null,"form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"}},"localOverride":false},"CachedAsset:component:custom.widget.MicrosoftFooter-en-1744400827777":{"__typename":"CachedAsset","id":"component:custom.widget.MicrosoftFooter-en-1744400827777","value":{"component":{"id":"custom.widget.MicrosoftFooter","template":{"id":"MicrosoftFooter","markupLanguage":"HANDLEBARS","style":".context-uhf {\n min-width: 280px;\n font-size: 15px;\n box-sizing: border-box;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n & *,\n & *:before,\n & *:after {\n box-sizing: inherit;\n }\n a.c-uhff-link {\n color: #616161;\n word-break: break-word;\n text-decoration: none;\n }\n &a:link,\n &a:focus,\n &a:hover,\n &a:active,\n &a:visited {\n text-decoration: none;\n color: inherit;\n }\n & div {\n font-family: 'Segoe UI', SegoeUI, 'Helvetica Neue', Helvetica, Arial, sans-serif;\n }\n}\n.c-uhff {\n background: #f2f2f2;\n margin: -1.5625;\n width: auto;\n height: auto;\n}\n.c-uhff-nav {\n margin: 0 auto;\n max-width: calc(1600px + 10%);\n padding: 0 5%;\n box-sizing: inherit;\n &:before,\n &:after {\n content: ' ';\n display: table;\n clear: left;\n }\n @media only screen and (max-width: 1083px) {\n padding-left: 12px;\n }\n .c-heading-4 {\n color: #616161;\n word-break: break-word;\n font-size: 15px;\n line-height: 20px;\n padding: 36px 0 4px;\n font-weight: 600;\n }\n .c-uhff-nav-row {\n .c-uhff-nav-group {\n display: block;\n float: left;\n min-height: 1px;\n vertical-align: text-top;\n padding: 0 12px;\n width: 100%;\n zoom: 1;\n &:first-child {\n padding-left: 0;\n @media only screen and (max-width: 1083px) {\n padding-left: 12px;\n }\n }\n @media only screen and (min-width: 540px) and (max-width: 1082px) {\n width: 33.33333%;\n }\n @media only screen and (min-width: 1083px) {\n width: 16.6666666667%;\n }\n ul.c-list.f-bare {\n font-size: 11px;\n line-height: 16px;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n list-style-type: none;\n li {\n word-break: break-word;\n padding: 8px 0;\n margin: 0;\n }\n }\n }\n }\n}\n.c-uhff-base {\n background: #f2f2f2;\n margin: 0 auto;\n max-width: calc(1600px + 10%);\n padding: 30px 5% 16px;\n &:before,\n &:after {\n content: ' ';\n display: table;\n }\n &:after {\n clear: both;\n }\n a.c-uhff-ccpa {\n font-size: 11px;\n line-height: 16px;\n float: left;\n margin: 3px 0;\n }\n a.c-uhff-ccpa:hover {\n text-decoration: underline;\n }\n ul.c-list {\n font-size: 11px;\n line-height: 16px;\n float: right;\n margin: 3px 0;\n color: #616161;\n li {\n padding: 0 24px 4px 0;\n display: inline-block;\n }\n }\n .c-list.f-bare {\n padding-left: 0;\n list-style-type: none;\n }\n @media only screen and (max-width: 1083px) {\n display: flex;\n flex-wrap: wrap;\n padding: 30px 24px 16px;\n }\n}\n\n.social-share {\n position: fixed;\n top: 60%;\n transform: translateY(-50%);\n left: 0;\n z-index: 1000;\n}\n\n.sharing-options {\n list-style: none;\n padding: 0;\n margin: 0;\n display: block;\n flex-direction: column;\n background-color: white;\n width: 43px;\n border-radius: 0px 7px 7px 0px;\n}\n.linkedin-icon {\n border-top-right-radius: 7px;\n}\n.linkedin-icon:hover {\n border-radius: 0;\n}\n.social-share-rss-image {\n border-bottom-right-radius: 7px;\n}\n.social-share-rss-image:hover {\n border-radius: 0;\n}\n\n.social-link-footer {\n position: relative;\n display: block;\n margin: -2px 0;\n transition: all 0.2s ease;\n}\n.social-link-footer:hover .linkedin-icon {\n border-radius: 0;\n}\n.social-link-footer:hover .social-share-rss-image {\n border-radius: 0;\n}\n\n.social-link-footer img {\n width: 40px;\n height: auto;\n transition: filter 0.3s ease;\n}\n\n.social-share-list {\n width: 40px;\n}\n.social-share-rss-image {\n width: 40px;\n}\n\n.share-icon {\n border: 2px solid transparent;\n display: inline-block;\n position: relative;\n}\n\n.share-icon:hover {\n opacity: 1;\n border: 2px solid white;\n box-sizing: border-box;\n}\n\n.share-icon:hover .label {\n opacity: 1;\n visibility: visible;\n border: 2px solid white;\n box-sizing: border-box;\n border-left: none;\n}\n\n.label {\n position: absolute;\n left: 100%;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n color: white;\n border-radius: 0 10 0 10px;\n top: 50%;\n transform: translateY(-50%);\n height: 40px;\n border-radius: 0 6px 6px 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 20px 5px 20px 8px;\n margin-left: -1px;\n}\n.linkedin {\n background-color: #0474b4;\n}\n.facebook {\n background-color: #3c5c9c;\n}\n.twitter {\n background-color: white;\n color: black;\n}\n.reddit {\n background-color: #fc4404;\n}\n.mail {\n background-color: #848484;\n}\n.bluesky {\n background-color: white;\n color: black;\n}\n.rss {\n background-color: #ec7b1c;\n}\n#RSS {\n width: 40px;\n height: 40px;\n}\n\n@media (max-width: 991px) {\n .social-share {\n display: none;\n }\n}\n","texts":{"New tab":"What's New","New 1":"Surface Laptop Studio 2","New 2":"Surface Laptop Go 3","New 3":"Surface Pro 9","New 4":"Surface Laptop 5","New 5":"Surface Studio 2+","New 6":"Copilot in Windows","New 7":"Microsoft 365","New 8":"Windows 11 apps","Store tab":"Microsoft Store","Store 1":"Account Profile","Store 2":"Download Center","Store 3":"Microsoft Store Support","Store 4":"Returns","Store 5":"Order tracking","Store 6":"Certified Refurbished","Store 7":"Microsoft Store Promise","Store 8":"Flexible Payments","Education tab":"Education","Edu 1":"Microsoft in education","Edu 2":"Devices for education","Edu 3":"Microsoft Teams for Education","Edu 4":"Microsoft 365 Education","Edu 5":"How to buy for your school","Edu 6":"Educator Training and development","Edu 7":"Deals for students and parents","Edu 8":"Azure for students","Business tab":"Business","Bus 1":"Microsoft Cloud","Bus 2":"Microsoft Security","Bus 3":"Dynamics 365","Bus 4":"Microsoft 365","Bus 5":"Microsoft Power Platform","Bus 6":"Microsoft Teams","Bus 7":"Microsoft Industry","Bus 8":"Small Business","Developer tab":"Developer & IT","Dev 1":"Azure","Dev 2":"Developer Center","Dev 3":"Documentation","Dev 4":"Microsoft Learn","Dev 5":"Microsoft Tech Community","Dev 6":"Azure Marketplace","Dev 7":"AppSource","Dev 8":"Visual Studio","Company tab":"Company","Com 1":"Careers","Com 2":"About Microsoft","Com 3":"Company News","Com 4":"Privacy at Microsoft","Com 5":"Investors","Com 6":"Diversity and inclusion","Com 7":"Accessiblity","Com 8":"Sustainibility"},"defaults":{"config":{"applicablePages":[],"description":"The Microsoft Footer","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.MicrosoftFooter","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"The Microsoft Footer","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":{"css":".custom_widget_MicrosoftFooter_context-uhf_105bp_1 {\n min-width: 17.5rem;\n font-size: 0.9375rem;\n box-sizing: border-box;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n & *,\n & *:before,\n & *:after {\n box-sizing: inherit;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-link_105bp_12 {\n color: #616161;\n word-break: break-word;\n text-decoration: none;\n }\n &a:link,\n &a:focus,\n &a:hover,\n &a:active,\n &a:visited {\n text-decoration: none;\n color: inherit;\n }\n & div {\n font-family: 'Segoe UI', SegoeUI, 'Helvetica Neue', Helvetica, Arial, sans-serif;\n }\n}\n.custom_widget_MicrosoftFooter_c-uhff_105bp_12 {\n background: #f2f2f2;\n margin: -1.5625;\n width: auto;\n height: auto;\n}\n.custom_widget_MicrosoftFooter_c-uhff-nav_105bp_35 {\n margin: 0 auto;\n max-width: calc(100rem + 10%);\n padding: 0 5%;\n box-sizing: inherit;\n &:before,\n &:after {\n content: ' ';\n display: table;\n clear: left;\n }\n @media only screen and (max-width: 1083px) {\n padding-left: 0.75rem;\n }\n .custom_widget_MicrosoftFooter_c-heading-4_105bp_49 {\n color: #616161;\n word-break: break-word;\n font-size: 0.9375rem;\n line-height: 1.25rem;\n padding: 2.25rem 0 0.25rem;\n font-weight: 600;\n }\n .custom_widget_MicrosoftFooter_c-uhff-nav-row_105bp_57 {\n .custom_widget_MicrosoftFooter_c-uhff-nav-group_105bp_58 {\n display: block;\n float: left;\n min-height: 0.0625rem;\n vertical-align: text-top;\n padding: 0 0.75rem;\n width: 100%;\n zoom: 1;\n &:first-child {\n padding-left: 0;\n @media only screen and (max-width: 1083px) {\n padding-left: 0.75rem;\n }\n }\n @media only screen and (min-width: 540px) and (max-width: 1082px) {\n width: 33.33333%;\n }\n @media only screen and (min-width: 1083px) {\n width: 16.6666666667%;\n }\n ul.custom_widget_MicrosoftFooter_c-list_105bp_78.custom_widget_MicrosoftFooter_f-bare_105bp_78 {\n font-size: 0.6875rem;\n line-height: 1rem;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n list-style-type: none;\n li {\n word-break: break-word;\n padding: 0.5rem 0;\n margin: 0;\n }\n }\n }\n }\n}\n.custom_widget_MicrosoftFooter_c-uhff-base_105bp_94 {\n background: #f2f2f2;\n margin: 0 auto;\n max-width: calc(100rem + 10%);\n padding: 1.875rem 5% 1rem;\n &:before,\n &:after {\n content: ' ';\n display: table;\n }\n &:after {\n clear: both;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107 {\n font-size: 0.6875rem;\n line-height: 1rem;\n float: left;\n margin: 0.1875rem 0;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107:hover {\n text-decoration: underline;\n }\n ul.custom_widget_MicrosoftFooter_c-list_105bp_78 {\n font-size: 0.6875rem;\n line-height: 1rem;\n float: right;\n margin: 0.1875rem 0;\n color: #616161;\n li {\n padding: 0 1.5rem 0.25rem 0;\n display: inline-block;\n }\n }\n .custom_widget_MicrosoftFooter_c-list_105bp_78.custom_widget_MicrosoftFooter_f-bare_105bp_78 {\n padding-left: 0;\n list-style-type: none;\n }\n @media only screen and (max-width: 1083px) {\n display: flex;\n flex-wrap: wrap;\n padding: 1.875rem 1.5rem 1rem;\n }\n}\n.custom_widget_MicrosoftFooter_social-share_105bp_138 {\n position: fixed;\n top: 60%;\n transform: translateY(-50%);\n left: 0;\n z-index: 1000;\n}\n.custom_widget_MicrosoftFooter_sharing-options_105bp_146 {\n list-style: none;\n padding: 0;\n margin: 0;\n display: block;\n flex-direction: column;\n background-color: white;\n width: 2.6875rem;\n border-radius: 0 0.4375rem 0.4375rem 0;\n}\n.custom_widget_MicrosoftFooter_linkedin-icon_105bp_156 {\n border-top-right-radius: 7px;\n}\n.custom_widget_MicrosoftFooter_linkedin-icon_105bp_156:hover {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n border-bottom-right-radius: 7px;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162:hover {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169 {\n position: relative;\n display: block;\n margin: -0.125rem 0;\n transition: all 0.2s ease;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169:hover .custom_widget_MicrosoftFooter_linkedin-icon_105bp_156 {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169:hover .custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169 img {\n width: 2.5rem;\n height: auto;\n transition: filter 0.3s ease;\n}\n.custom_widget_MicrosoftFooter_social-share-list_105bp_188 {\n width: 2.5rem;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n width: 2.5rem;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195 {\n border: 2px solid transparent;\n display: inline-block;\n position: relative;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195:hover {\n opacity: 1;\n border: 2px solid white;\n box-sizing: border-box;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195:hover .custom_widget_MicrosoftFooter_label_105bp_207 {\n opacity: 1;\n visibility: visible;\n border: 2px solid white;\n box-sizing: border-box;\n border-left: none;\n}\n.custom_widget_MicrosoftFooter_label_105bp_207 {\n position: absolute;\n left: 100%;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n color: white;\n border-radius: 0 10 0 0.625rem;\n top: 50%;\n transform: translateY(-50%);\n height: 2.5rem;\n border-radius: 0 0.375rem 0.375rem 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1.25rem 0.3125rem 1.25rem 0.5rem;\n margin-left: -0.0625rem;\n}\n.custom_widget_MicrosoftFooter_linkedin_105bp_156 {\n background-color: #0474b4;\n}\n.custom_widget_MicrosoftFooter_facebook_105bp_237 {\n background-color: #3c5c9c;\n}\n.custom_widget_MicrosoftFooter_twitter_105bp_240 {\n background-color: white;\n color: black;\n}\n.custom_widget_MicrosoftFooter_reddit_105bp_244 {\n background-color: #fc4404;\n}\n.custom_widget_MicrosoftFooter_mail_105bp_247 {\n background-color: #848484;\n}\n.custom_widget_MicrosoftFooter_bluesky_105bp_250 {\n background-color: white;\n color: black;\n}\n.custom_widget_MicrosoftFooter_rss_105bp_254 {\n background-color: #ec7b1c;\n}\n#custom_widget_MicrosoftFooter_RSS_105bp_1 {\n width: 2.5rem;\n height: 2.5rem;\n}\n@media (max-width: 991px) {\n .custom_widget_MicrosoftFooter_social-share_105bp_138 {\n display: none;\n }\n}\n","tokens":{"context-uhf":"custom_widget_MicrosoftFooter_context-uhf_105bp_1","c-uhff-link":"custom_widget_MicrosoftFooter_c-uhff-link_105bp_12","c-uhff":"custom_widget_MicrosoftFooter_c-uhff_105bp_12","c-uhff-nav":"custom_widget_MicrosoftFooter_c-uhff-nav_105bp_35","c-heading-4":"custom_widget_MicrosoftFooter_c-heading-4_105bp_49","c-uhff-nav-row":"custom_widget_MicrosoftFooter_c-uhff-nav-row_105bp_57","c-uhff-nav-group":"custom_widget_MicrosoftFooter_c-uhff-nav-group_105bp_58","c-list":"custom_widget_MicrosoftFooter_c-list_105bp_78","f-bare":"custom_widget_MicrosoftFooter_f-bare_105bp_78","c-uhff-base":"custom_widget_MicrosoftFooter_c-uhff-base_105bp_94","c-uhff-ccpa":"custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107","social-share":"custom_widget_MicrosoftFooter_social-share_105bp_138","sharing-options":"custom_widget_MicrosoftFooter_sharing-options_105bp_146","linkedin-icon":"custom_widget_MicrosoftFooter_linkedin-icon_105bp_156","social-share-rss-image":"custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162","social-link-footer":"custom_widget_MicrosoftFooter_social-link-footer_105bp_169","social-share-list":"custom_widget_MicrosoftFooter_social-share-list_105bp_188","share-icon":"custom_widget_MicrosoftFooter_share-icon_105bp_195","label":"custom_widget_MicrosoftFooter_label_105bp_207","linkedin":"custom_widget_MicrosoftFooter_linkedin_105bp_156","facebook":"custom_widget_MicrosoftFooter_facebook_105bp_237","twitter":"custom_widget_MicrosoftFooter_twitter_105bp_240","reddit":"custom_widget_MicrosoftFooter_reddit_105bp_244","mail":"custom_widget_MicrosoftFooter_mail_105bp_247","bluesky":"custom_widget_MicrosoftFooter_bluesky_105bp_250","rss":"custom_widget_MicrosoftFooter_rss_105bp_254","RSS":"custom_widget_MicrosoftFooter_RSS_105bp_1"}},"form":null},"localOverride":false},"CachedAsset:text:en_US-components/community/Breadcrumb-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/community/Breadcrumb-1744658876111","value":{"navLabel":"Breadcrumbs","dropdown":"Additional parent page navigation"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagsHeaderWidget-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagsHeaderWidget-1744658876111","value":{"tag":"{tagName}","topicsCount":"{count} {count, plural, one {Topic} other {Topics}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1744658876111","value":{"title@userScope:other":"Recent Content","title@userScope:self":"Contributions","title@board:FORUM@userScope:other":"Recent Discussions","title@board:BLOG@userScope:other":"Recent Blogs","emptyDescription":"No content to show","MessageListForNodeByRecentActivityWidgetEditor.nodeScope.label":"Scope","title@instance:1722894000155":"Recent Discussions","title@instance:1727367112619":"Recent Blog Articles","title@instance:1727367069748":"Recent Discussions","title@instance:1727366213114":"Latest Discussions","title@instance:1727899609720":"","title@instance:1727363308925":"Latest Discussions","title@instance:1737115580352":"Latest Articles","title@instance:1720453418992":"Recent Discssions","title@instance:1727365950181":"Latest Blog Articles","title@instance:bmDPnI":"Latest Blog Articles","title@instance:IiDDJZ":"Latest Blog Articles","title@instance:1721244347979":"Latest blog posts","title@instance:1728383752171":"Related Content","title@instance:1722893956545":"Latest Skilling Resources","title@instance:dhcgCU":"Latest Discussions"},"localOverride":false},"Category:category:Exchange":{"__typename":"Category","id":"category:Exchange","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Planner":{"__typename":"Category","id":"category:Planner","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Outlook":{"__typename":"Category","id":"category:Outlook","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Community-Info-Center":{"__typename":"Category","id":"category:Community-Info-Center","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:EducationSector":{"__typename":"Category","id":"category:EducationSector","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:DrivingAdoption":{"__typename":"Category","id":"category:DrivingAdoption","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Windows-Server":{"__typename":"Category","id":"category:Windows-Server","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:SQL-Server":{"__typename":"Category","id":"category:SQL-Server","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftTeams":{"__typename":"Category","id":"category:MicrosoftTeams","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:PublicSector":{"__typename":"Category","id":"category:PublicSector","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoft365":{"__typename":"Category","id":"category:microsoft365","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:IoT":{"__typename":"Category","id":"category:IoT","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:HealthcareAndLifeSciences":{"__typename":"Category","id":"category:HealthcareAndLifeSciences","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:SMB":{"__typename":"Category","id":"category:SMB","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:ITOpsTalk":{"__typename":"Category","id":"category:ITOpsTalk","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoft-endpoint-manager":{"__typename":"Category","id":"category:microsoft-endpoint-manager","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftLearn":{"__typename":"Category","id":"category:MicrosoftLearn","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Blog:board:MicrosoftLearnBlog":{"__typename":"Blog","id":"board:MicrosoftLearnBlog","blogPolicies":{"__typename":"BlogPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:AI":{"__typename":"Category","id":"category:AI","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftMechanics":{"__typename":"Category","id":"category:MicrosoftMechanics","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:StartupsatMicrosoft":{"__typename":"Category","id":"category:StartupsatMicrosoft","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:PartnerCommunity":{"__typename":"Category","id":"category:PartnerCommunity","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Windows":{"__typename":"Category","id":"category:Windows","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoft-security":{"__typename":"Category","id":"category:microsoft-security","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Conversation:conversation:4398616":{"__typename":"Conversation","id":"conversation:4398616","topic":{"__typename":"BlogTopicMessage","uid":4398616},"lastPostingActivityTime":"2025-03-28T22:32:35.234-07:00","solved":false},"User:user:1357822":{"__typename":"User","uid":1357822,"login":"theringe","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/dS0xMzU3ODIyLXNoNVM5ZA?image-coordinates=0%2C0%2C1280%2C1280"},"id":"user:1357822"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LXg1RlpDag?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LXg1RlpDag?revision=3","title":"image.png","associationType":"BODY","width":775,"height":1337,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWUwMnZvZg?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWUwMnZvZg?revision=3","title":"image.png","associationType":"BODY","width":1517,"height":256,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LVRGUjdXTw?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LVRGUjdXTw?revision=3","title":"image.png","associationType":"BODY","width":606,"height":1084,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LTdCdVpVVQ?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LTdCdVpVVQ?revision=3","title":"image.png","associationType":"BODY","width":1130,"height":549,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LU95M3NZYw?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LU95M3NZYw?revision=3","title":"image.png","associationType":"BODY","width":1311,"height":1129,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LTI2REhnaw?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LTI2REhnaw?revision=3","title":"image.png","associationType":"BODY","width":1734,"height":928,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LUdRUHJKcw?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LUdRUHJKcw?revision=3","title":"image.png","associationType":"BODY","width":2474,"height":1597,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWtoQ2w2Sg?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWtoQ2w2Sg?revision=3","title":"image.png","associationType":"BODY","width":2474,"height":1597,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWJTYjBOOQ?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWJTYjBOOQ?revision=3","title":"image.png","associationType":"BODY","width":1823,"height":1537,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LUlQMHZNcA?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LUlQMHZNcA?revision=3","title":"image.png","associationType":"BODY","width":1774,"height":1230,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LUVkR3ozWA?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LUVkR3ozWA?revision=3","title":"image.png","associationType":"BODY","width":1778,"height":1135,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LVhQTnJiag?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LVhQTnJiag?revision=3","title":"image.png","associationType":"BODY","width":616,"height":229,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LVprbHNwcQ?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LVprbHNwcQ?revision=3","title":"image.png","associationType":"BODY","width":1151,"height":728,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LXFkUnFmWg?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LXFkUnFmWg?revision=3","title":"clipboard_image-1-1743218620673.png","associationType":"BODY","width":1344,"height":520,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWtWcTFkaQ?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWtWcTFkaQ?revision=3","title":"clipboard_image-2-1743218620674.png","associationType":"BODY","width":1316,"height":505,"altText":""},"BlogTopicMessage:message:4398616":{"__typename":"BlogTopicMessage","subject":"Superfast Installing Code Push Server in a Windows Web App","conversation":{"__ref":"Conversation:conversation:4398616"},"id":"message:4398616","revisionNum":3,"uid":4398616,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:1357822"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"This method allows you to setup Code Push Server in a Windows Web App","metrics":{"__typename":"MessageMetrics","views":417},"postTime":"2025-03-28T20:23:57.038-07:00","lastPublishTime":"2025-03-28T22:32:35.234-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" TOC \n \n Introduction \n Setup \n Debugging \n References \n \n 1. Introduction \n CodePush Server is a self-hosted backend for Microsoft CodePush, allowing you to manage and deploy over-the-air updates for React Native and Cordova apps. It provides update versioning, deployment history, and authentication controls. \n It is typically designed to run on Linux-based Node environments. If you want to deploy it on Azure Windows Web App, you can follow this tutorial to apply the necessary modifications. \n 2. Setup \n 1. Create a Windows Node.js Web App. In this example, we use Node.js 20 LTS. \n \n   \n   \n 2. After the Web App is created, go to the Overview tab and copy its FQDN. You'll need this in later steps. \n \n   \n   \n 3. Create a standard Storage Account. \n \n   \n   \n 4. Once created, go to Access keys and copy the Storage Account’s name and key for later use. \n \n   \n   \n 5. Return to the Web App's Environment Variables and add the following configuration values. \n \n Variable Name \n \n Variable Value \n \n AZURE_STORAGE_ACCOUNT \n \n <Storage Account name you've copied from step 4> \n \n AZURE_STORAGE_ACCESS_KEY \n \n <Storage Account key you've copied from step 4> \n \n SERVER_URL \n \n <https:// + Web app FQDN you've copied from step 2> \n e.g., https://az-7135-app.azurewebsites.net \n \n CORS_ORIGIN \n \n <https:// + Web app FQDN you've copied from step 2> \n e.g., https://az-7135-app.azurewebsites.net \n \n LOGGING \n \n false \n \n \n   \n   \n 6. On your local machine, open a terminal and clone the CodePush Server source code. Then create your own project folder—for example, az-7135-app. \n # Change to you working dir and your project name (e.g, az-7135-app)\ngit clone https://github.com/microsoft/code-push-server.git\nmkdir az-7135-app\ncp -R code-push-server/api/* az-7135-app\ncp az-7135-app/.env.example az-7135-app/.env \n   \n 7. Open the project folder in VSCode, create server.js and web.config, and modify the relevant files as described. \n \n File name \n \n Change \n \n Reason \n \n .env \n \n Please setup AZURE_STORAGE_ACCOUNT, AZURE_STORAGE_ACCESS_KEY, and SERVER_URL follow step 4 \n \n From Official Tutorial Bicep Template \n \n web.config \n \n <?xml version=\"1.0\" encoding=\"utf-8\"?> \n <configuration> \n   <system.webServer> \n     <handlers> \n       <add name=\"iisnode\" path=\"server.js\" verb=\"*\" modules=\"iisnode\" /> \n     </handlers> \n     <rewrite> \n       <rules> \n         <rule name=\"NodeJsApp\" stopProcessing=\"true\"> \n           <match url=\".*\" /> \n           <action type=\"Rewrite\" url=\"server.js\" /> \n         </rule> \n       </rules> \n     </rewrite> \n     <iisnode \n       loggingEnabled=\"false\" \n       debuggingEnabled=\"true\" \n       devErrorsEnabled=\"true\" \n     /> \n   </system.webServer> \n </configuration> \n \n When using a Windows App, the HTTP server is IIS. As a reverse proxy, IIS needs to forward incoming requests to another web server running on the same machine—in this case, node.exe. \n Due to several path limitations in web.config (such as not supporting nested directories for the entry point), the server.js file must reside in the same directory as web.config. Since the original project uses bin/script/server.js as the entry point, which cannot be directly referenced here, you need to create a new server.js file in the root directory as a wrapper to forward execution. \n The iisnode section in web.config is useful for debugging purposes. However, it requires the debugging settings described below to work correctly. Once debugging is complete, this section can be safely removed. \n \n server.js \n \n // Wrapper to launch actual entry point \n require(\"./bin/script/server.js\"); \n \n Same as above \n \n script/server.ts \n \n   //const port: number = Number(process.env.API_PORT) || Number(process.env.PORT) || defaultPort; \n   const port: number = process.env.API_PORT || process.env.PORT || defaultPort; \n \n All traffic in Windows Web Apps is routed through IIS to node.exe, so the actual listening port is not a traditional number but a system-generated internal pipe (e.g., \\\\.\\pipe\\dff22378-aeb3-4ede-8d1e-7c1e1bdc0c46). Therefore, adjustments are needed to align with this architecture. \n \n package.json \n \n Before: \"main\": \"./script/server.js\", \n After: \"main\": \"server.js\", \n   \n Before: \"start\": \"node ./bin/script/server.js\", \n After: \"start\": \"node server.js\", \n   \n Before: \"start:env\": \"node -r dotenv/config server.js dotenv_config_path=.env dotenv_config_silent=true\", \n After: \"start:env\": \"node -r dotenv/config server.js dotenv_config_path=.env dotenv_config_silent=true\", \n   \n Before: \"build\": \"tsc && shx cp -r ./script/views ./bin/script\", \n After: \"build\": \"npm install typescript --save-dev && tsc && shx cp -r ./script/views ./bin/script\", \n \n Like web.config, we change most entry points to use a root-level server.js instead of a path with nested folders. \n Additionally, note that the Oryx build process differs between Windows and Linux Web Apps. On Windows, the build step only runs npm install and npm run start, but not npm run build. Also, the underlying OS doesn’t come with TypeScript pre-installed. This causes npm run build to fail unless adjusted. \n To resolve this, modify the build script to include TypeScript installation. After deployment, you must also manually run npm run build once using the Kudu interface. \n \n \n   \n   \n 8. Use VSCode to publish the project. Then, in the Azure Portal's Web App Deployment Center, wait for the deployment to complete. This may take around 10 minutes, and this step alone doesn't mean the app is ready to run. \n \n   \n   \n 9. Open the Kudu interface. Here, you need to perform the task mentioned in step 7: manually run npm run build once. This will generate the bin folder containing the compiled runtime code. This process takes about 5 minutes. \n \n   \n   \n 10. With the build complete, the deployment process is finished. You can now visit the Web App's homepage. The first load may take up to 30 seconds due to cold start; subsequent requests will be faster. \n \n   \n 3. Debugging \n If you need to debug, enable App Service Logs and ensure that your web.config in step 7 has the appropriate debug settings. \n \n   \n Once enabled, go to the Kudu interface, navigate to the LogFiles/Application folder, and review the stdout and stderr logs generated by node.exe. \n \n   \n 4. References \n code-push-server/api at main · microsoft/code-push-server \n Troubleshooting Common iisnode Issues - ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"7190","kudosSumWeight":0,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LXg1RlpDag?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWUwMnZvZg?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LVRGUjdXTw?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LTdCdVpVVQ?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LU95M3NZYw?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LTI2REhnaw?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDc","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LUdRUHJKcw?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDg","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWtoQ2w2Sg?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDk","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWJTYjBOOQ?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEw","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LUlQMHZNcA?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEx","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LUVkR3ozWA?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEy","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LVhQTnJiag?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEz","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LVprbHNwcQ?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE0","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LXFkUnFmWg?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE1","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4NjE2LWtWcTFkaQ?revision=3\"}"}}],"totalCount":15,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:4398187":{"__typename":"Conversation","id":"conversation:4398187","topic":{"__typename":"BlogTopicMessage","uid":4398187},"lastPostingActivityTime":"2025-03-27T14:13:33.387-07:00","solved":false},"User:user:360851":{"__typename":"User","uid":360851,"login":"madhurabharadwaj","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/dS0zNjA4NTEtMjUyNjg5aTcxMkE1Njk5MjBBM0JFODU"},"id":"user:360851"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4MTg3LUZNRFd3SQ?revision=3\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4MTg3LUZNRFd3SQ?revision=3","title":"FunctionsLogopng.png","associationType":"COVER","width":600,"height":315,"altText":""},"BlogTopicMessage:message:4398187":{"__typename":"BlogTopicMessage","subject":"Keep Your Azure Functions Up to Date: Identify Apps Running on Retired Versions","conversation":{"__ref":"Conversation:conversation:4398187"},"id":"message:4398187","revisionNum":3,"uid":4398187,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:360851"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"Ensure your Azure Functions stay supported and secure with these Azure CLI scripts, helping you identify and upgrade apps running on soon-to-be-retired or unsupported language versions.","metrics":{"__typename":"MessageMetrics","views":730},"postTime":"2025-03-27T14:13:33.387-07:00","lastPublishTime":"2025-03-27T14:13:33.387-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Running Azure Functions on retired language versions can lead to security risks, performance issues, and potential service disruptions. While Azure Functions Team notifies users about upcoming retirements through the portal, emails, and warnings, identifying affected Function Apps across multiple subscriptions can be challenging. \n To simplify this, we’ve provided Azure CLI scripts to help you: ✅ Identify all Function Apps using a specific runtime version ✅ Find apps running on unsupported or soon-to-be-retired versions ✅ Take proactive steps to upgrade and maintain a secure, supported environment \n Read on for the full set of Azure CLI scripts and instructions on how to upgrade your apps today! \n Why Upgrading Your Azure Functions Matters \n Azure Functions supports six different programming languages, with new stack versions being introduced and older ones retired regularly. Staying on a supported language version is critical to ensure: \n \n Continued access to support and security updates \n Avoidance of performance degradation and unexpected failures \n Compliance with best practices for cloud reliability \n \n Failure to upgrade can lead to security vulnerabilities, performance issues, and unsupported workloads that may eventually break. Azure's language support policy follows a structured deprecation timeline, which you can review here. \n How Will You Know When a Version Is Nearing its End-of-Life? \n The Azure Functions team communicates retirements well in advance through multiple channels: \n \n Azure Portal notifications \n Emails to subscription owners \n Warnings in client tools and Azure Portal UI when an app is running on a version that is either retired, or about to be retired in the next 6 months \n Official Azure Functions Supported Languages document here \n \n To help you track these changes, we recommend reviewing the language version support timelines in the Azure Functions Supported Languages document. \n However, identifying all affected apps across multiple subscriptions can be challenging. To simplify this process, I've built some Azure CLI scripts below that can help you list all impacted Function Apps in your environment. \n   \n Linux* Function Apps with their language stack versions: \n \n az functionapp list --query \"[?siteConfig.linuxFxVersion!=null && siteConfig.linuxFxVersion!=''].{Name:name, ResourceGroup:resourceGroup, OS:'Linux', LinuxFxVersion:siteConfig.linuxFxVersion}\" --output table  \n \n *Running on Elastic Premium and App Service Plans \n   \n Linux* Function Apps on a specific language stack version: Ex: Node.js 18 \n \n az functionapp list --query \"[?siteConfig.linuxFxVersion=='Node|18'].{Name:name, ResourceGroup:resourceGroup, OS: 'Linux', LinuxFxVersion:siteConfig.linuxFxVersion}\" --output table  \n \n *Running on Elastic Premium and App Service Plans \n   \n Windows Function Apps only:  \n \n az functionapp list --query \"[?!contains(kind, 'linux')].{Name:name, ResourceGroup:resourceGroup, OS:'Windows'}\" --output table  \n \n   \n Windows Function Apps with their language stack versions:  \n \n az functionapp list --query \"[?!contains(kind, 'linux')].{name: name, resourceGroup: resourceGroup}\" -o json | ConvertFrom-Json | ForEach-Object {  \n     $appSettings = az functionapp config appsettings list -n $_.name -g $_.resourceGroup --query \"[?name=='FUNCTIONS_WORKER_RUNTIME' || name=='WEBSITE_NODE_DEFAULT_VERSION']\" -o json | ConvertFrom-Json  \n      $siteConfig = az functionapp config show -n $_.name -g $_.resourceGroup --query \"{powerShellVersion: powerShellVersion, netFrameworkVersion: netFrameworkVersion, javaVersion: javaVersion}\" -o json | ConvertFrom-Json  \n        \n      $runtime = ($appSettings | Where-Object { $_.name -eq 'FUNCTIONS_WORKER_RUNTIME' }).value  \n      $version = switch($runtime) {  \n          'node' { ($appSettings | Where-Object { $_.name -eq 'WEBSITE_NODE_DEFAULT_VERSION' }).value }  \n          'powershell' { $siteConfig.powerShellVersion }  \n          'dotnet' { $siteConfig.netFrameworkVersion }  \n          'java' { $siteConfig.javaVersion }  \n          default { 'Unknown' }  \n      }  \n        \n      [PSCustomObject]@{  \n          Name = $_.name  \n          ResourceGroup = $_.resourceGroup  \n          OS = 'Windows'  \n          Runtime = $runtime  \n          Version = $version  \n      }  \n  } | Format-Table -AutoSize  \n \n   \n Windows Function Apps running on Node.js runtime:  \n \n az functionapp list --query \"[?!contains(kind, 'linux')].{name: name, resourceGroup: resourceGroup}\" -o json | ConvertFrom-Json | ForEach-Object {  \n     $appSettings = az functionapp config appsettings list -n $_.name -g $_.resourceGroup --query \"[?name=='FUNCTIONS_WORKER_RUNTIME' || name=='WEBSITE_NODE_DEFAULT_VERSION']\" -o json | ConvertFrom-Json  \n       \n     $runtime = ($appSettings | Where-Object { $_.name -eq 'FUNCTIONS_WORKER_RUNTIME' }).value  \n     if ($runtime -eq 'node') {  \n         $version = ($appSettings | Where-Object { $_.name -eq 'WEBSITE_NODE_DEFAULT_VERSION' }).value  \n           \n         [PSCustomObject]@{  \n             Name = $_.name  \n             ResourceGroup = $_.resourceGroup  \n             OS = 'Windows'  \n             Runtime = $runtime  \n             Version = $version  \n         }  \n     }  \n } | Format-Table -AutoSize  \n \n   \n Windows Function Apps running on a specific language version: Ex: Node.js 18 \n \n az functionapp list --query \"[?!contains(kind, 'linux')].{name: name, resourceGroup: resourceGroup}\" -o json | ConvertFrom-Json | ForEach-Object {  \n     $appSettings = az functionapp config appsettings list -n $_.name -g $_.resourceGroup --query \"[?name=='FUNCTIONS_WORKER_RUNTIME' || name=='WEBSITE_NODE_DEFAULT_VERSION']\" -o json | ConvertFrom-Json  \n       \n     $runtime = ($appSettings | Where-Object { $_.name -eq 'FUNCTIONS_WORKER_RUNTIME' }).value  \n     $nodeVersion = ($appSettings | Where-Object { $_.name -eq 'WEBSITE_NODE_DEFAULT_VERSION' }).value  \n       \n     if ($runtime -eq 'node' -and $nodeVersion -eq '~18') {  \n         [PSCustomObject]@{  \n             Name = $_.name  \n             ResourceGroup = $_.resourceGroup  \n             OS = 'Windows'  \n             Runtime = $runtime  \n             Version = $nodeVersion  \n         }  \n     }  \n } | Format-Table -AutoSize  \n \n   \n All windows Apps running on unsupported language runtimes: (as of March 2025) \n \n az functionapp list --query \"[?!contains(kind, 'linux')].{name: name, resourceGroup: resourceGroup}\" -o json | ConvertFrom-Json | ForEach-Object {  \n     $appSettings = az functionapp config appsettings list -n $_.name -g $_.resourceGroup --query \"[?name=='FUNCTIONS_WORKER_RUNTIME' || name=='WEBSITE_NODE_DEFAULT_VERSION']\" -o json | ConvertFrom-Json  \n     $siteConfig = az functionapp config show -n $_.name -g $_.resourceGroup --query \"{powerShellVersion: powerShellVersion, netFrameworkVersion: netFrameworkVersion}\" -o json | ConvertFrom-Json  \n       \n     $runtime = ($appSettings | Where-Object { $_.name -eq 'FUNCTIONS_WORKER_RUNTIME' }).value  \n     $version = switch($runtime) {  \n         'node' {   \n             $nodeVer = ($appSettings | Where-Object { $_.name -eq 'WEBSITE_NODE_DEFAULT_VERSION' }).value  \n             if ([string]::IsNullOrEmpty($nodeVer)) { 'Unknown' } else { $nodeVer }  \n         }  \n         'powershell' { $siteConfig.powerShellVersion }  \n         'dotnet' { $siteConfig.netFrameworkVersion }  \n         default { 'Unknown' }  \n     }  \n       \n     # Check if runtime version is unsupported  \n     $isUnsupported = switch($runtime) {  \n         'node' {   \n             $ver = $version -replace '~',''  \n             [double]$ver -le 16  \n         }  \n         'powershell' {   \n             $ver = $version -replace '~',''  \n             [double]$ver -le 7.2  \n         }  \n         'dotnet' {   \n             $ver = $siteConfig.netFrameworkVersion  \n             $ver -notlike 'v7*' -and $ver -notlike 'v8*'  \n         }  \n         default { $false }  \n     }  \n       \n     if ($isUnsupported) {  \n         [PSCustomObject]@{  \n             Name = $_.name  \n             ResourceGroup = $_.resourceGroup  \n             OS = 'Windows'  \n             Runtime = $runtime  \n             Version = $version  \n         }  \n     }  \n } | Format-Table -AutoSize  \n \n Take Action Now \n By using these scripts, you can proactively identify and update Function Apps before they reach end-of-support status. Stay ahead of runtime retirements and ensure the reliability of your Function Apps.  \n For step-by-step instructions to upgrade your Function Apps, check out the Azure Functions Language version upgrade guide. \n For more details on Azure Functions' language support lifecycle, visit the official documentation. \n Have any questions? Let us know in the comments below! ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"9963","kudosSumWeight":1,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4MTg3LUZNRFd3SQ?revision=3\"}"}}],"totalCount":1,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":{"__typename":"UploadedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mzk4MTg3LUZNRFd3SQ?revision=3"},"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:4334985":{"__typename":"Conversation","id":"conversation:4334985","topic":{"__typename":"BlogTopicMessage","uid":4334985},"lastPostingActivityTime":"2025-03-05T21:11:20.931-08:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWxzR2dGRw?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWxzR2dGRw?revision=10","title":"image.png","associationType":"BODY","width":1043,"height":428,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTg2OEtiRQ?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTg2OEtiRQ?revision=10","title":"image.png","associationType":"BODY","width":480,"height":931,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LXZMZ3gzcw?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LXZMZ3gzcw?revision=10","title":"clipboard_image-2-1732514807383.png","associationType":"BODY","width":1476,"height":1177,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU1RbUNCSw?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU1RbUNCSw?revision=10","title":"clipboard_image-1-1732515042929.png","associationType":"BODY","width":1408,"height":627,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTAwUGJHVg?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTAwUGJHVg?revision=10","title":"clipboard_image-2-1732515077003.png","associationType":"BODY","width":2063,"height":1098,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU0yVnFjaA?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU0yVnFjaA?revision=10","title":"clipboard_image-3-1732515077003.png","associationType":"BODY","width":1398,"height":663,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU02VExIcg?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU02VExIcg?revision=10","title":"clipboard_image-4-1732515181422.png","associationType":"BODY","width":986,"height":975,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVQ1QkNuOQ?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVQ1QkNuOQ?revision=10","title":"clipboard_image-5-1732515181425.png","associationType":"BODY","width":1613,"height":835,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVZZZGdHWg?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVZZZGdHWg?revision=10","title":"clipboard_image-6-1732515218851.png","associationType":"BODY","width":1564,"height":833,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LUR2dzJSRQ?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LUR2dzJSRQ?revision=10","title":"clipboard_image-7-1732515218852.png","associationType":"BODY","width":742,"height":620,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWVKN2haVQ?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWVKN2haVQ?revision=10","title":"clipboard_image-8-1732515303545.png","associationType":"BODY","width":1514,"height":540,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWh4SlhNbA?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWh4SlhNbA?revision=10","title":"clipboard_image-9-1732515303547.png","associationType":"BODY","width":2017,"height":898,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU5aaDFQNQ?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU5aaDFQNQ?revision=10","title":"clipboard_image-10-1732515401213.png","associationType":"BODY","width":1414,"height":424,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTFBYkVKQw?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTFBYkVKQw?revision=10","title":"clipboard_image-11-1732515459689.png","associationType":"BODY","width":1421,"height":269,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LXk4SzF1WQ?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LXk4SzF1WQ?revision=10","title":"clipboard_image-1-1732515973753.png","associationType":"BODY","width":2039,"height":918,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LXc0UzJ4Rg?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LXc0UzJ4Rg?revision=10","title":"clipboard_image-2-1732515973753.png","associationType":"BODY","width":2045,"height":924,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTN5ZHdsNQ?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTN5ZHdsNQ?revision=10","title":"clipboard_image-3-1732516069673.png","associationType":"BODY","width":1438,"height":1209,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTE3VFBsbA?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTE3VFBsbA?revision=10","title":"clipboard_image-4-1732516069672.png","associationType":"BODY","width":513,"height":510,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LUtKZndsZQ?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LUtKZndsZQ?revision=10","title":"clipboard_image-5-1732516156474.png","associationType":"BODY","width":1835,"height":218,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTRXRmplVg?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTRXRmplVg?revision=10","title":"image.png","associationType":"BODY","width":928,"height":191,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVl6WWlFdw?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVl6WWlFdw?revision=10","title":"clipboard_image-6-1732516334371.png","associationType":"BODY","width":1693,"height":1263,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTJDbTZSYw?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTJDbTZSYw?revision=10","title":"clipboard_image-7-1732516334372.png","associationType":"BODY","width":1697,"height":1328,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LUtURjVTZg?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LUtURjVTZg?revision=10","title":"clipboard_image-8-1732516473317.png","associationType":"BODY","width":928,"height":191,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVBpd2htbw?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVBpd2htbw?revision=10","title":"clipboard_image-9-1732516473318.png","associationType":"BODY","width":1143,"height":339,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWtZNjBwQw?revision=10\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWtZNjBwQw?revision=10","title":"clipboard_image-10-1732516500054.png","associationType":"BODY","width":820,"height":508,"altText":""},"BlogTopicMessage:message:4334985":{"__typename":"BlogTopicMessage","subject":"Using OpenAI on Azure Web App","conversation":{"__ref":"Conversation:conversation:4334985"},"id":"message:4334985","revisionNum":10,"uid":4334985,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:1357822"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"On Azure Web Apps, you can use Python's OpenAI package to conveniently and quickly call the official API, upload your training data, and utilize their algorithms for processing. This tutorial provides a step-by-step guide to help you deploy your OpenAI project on an Azure Web App, covering everything from resource setup to troubleshooting common issues.","metrics":{"__typename":"MessageMetrics","views":943},"postTime":"2024-11-24T22:41:37.879-08:00","lastPublishTime":"2025-03-05T21:11:20.931-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" TOC \n \n Introduction to OpenAI \n System Architecture\n \n Architecture \n Focus of This Tutorial \n \n \n Setup Azure Resources\n \n File and Directory Structure \n ARM Template \n ARM Template From Azure Portal \n \n \n Running Locally \n \n Training Models and Training Data \n \n Predicting with the Model \n \n \n \n Publishing the Project to Azure \n Running on Azure Web App\n \n Training the Model \n Using the Model for Prediction \n \n \n Troubleshooting\n \n Startup Command Issue \n App Becomes Unresponsive After a Period \n az cli command for Linux webjobs fail \n Others \n \n \n Conclusion \n References \n \n 1. Introduction to OpenAI \n OpenAI is a leading artificial intelligence research and deployment company founded in December 2015. Its mission is to ensure that artificial general intelligence (AGI)—highly autonomous systems that outperform humans at most economically valuable work—benefits all of humanity. OpenAI focuses on developing safe and scalable AI technologies and ensuring equitable access to these innovations. \n   \n Known for its groundbreaking advancements in natural language processing, OpenAI has developed models like GPT (Generative Pre-trained Transformer), which powers applications for text generation, summarization, translation, and more. GPT models have revolutionized fields like conversational AI, creative writing, and programming assistance. OpenAI has also released models like Codex, designed to understand and generate computer code, and DALL·E, which creates images from textual descriptions. \n   \n OpenAI operates with a unique hybrid structure: a for-profit company governed by a nonprofit entity to balance the development of AI technology with ethical considerations. The organization emphasizes safety, research transparency, and alignment to human values. By providing access to its models through APIs and fostering partnerships, OpenAI empowers developers, businesses, and researchers to leverage AI for innovative solutions across diverse industries. Its long-term goal is to ensure AI advances benefit humanity as a whole. \n 2. System Architecture \n Architecture \n \n Development Environment \n \n OS:  \n \n Ubuntu \n \n Version:  \n \n Ubuntu 18.04 Bionic Beaver \n \n Python Version: \n \n 3.7.3 \n \n   \n Azure Resources \n \n App Service Plan: \n \n SKU - Premium Plan 0 V3 \n \n App Service: \n \n Platform - Linux (Python 3.9, Version 3.9.19) \n \n Storage Account: \n \n SKU - General Purpose V2 \n \n File Share: \n \n No backup plan \n \n   \n Focus of This Tutorial \n This tutorial walks you through the following stages: \n \n Setting up Azure resources \n Running the project locally \n Publishing the project to Azure \n Running the application on Azure \n Troubleshooting common issues \n \n Each of the mentioned aspects has numerous corresponding tools and solutions. The relevant information for this session is listed in the table below. \n   \n Local OS \n \n Windows \n \n Linux \n \n Mac \n \n   \n \n  V \n \n   \n \n   \n How to setup Azure resources \n \n Portal (i.e., REST api) \n \n ARM \n \n Bicep \n \n Terraform \n \n  V \n \n  V \n \n   \n \n   \n \n   \n How to deploy project to Azure \n \n VSCode \n \n CLI \n \n Azure DevOps \n \n GitHub Action \n \n   \n \n  V \n \n   \n \n   \n \n   \n 3. Setup Azure Resources \n File and Directory Structure \n Please open a bash terminal and enter the following commands: \n git clone https://github.com/theringe/azure-appservice-ai.git\ncd azure-appservice-ai\nbash ./openai/tools/add-venv.sh \n If you are using a Windows platform, use the following alternative PowerShell commands instead: \n git clone https://github.com/theringe/azure-appservice-ai.git\ncd azure-appservice-ai\n.\\openai\\tools\\add-venv.cmd \n   \n After completing the execution, you should see the following directory structure: \n \n   \n \n File and Path \n \n Purpose \n \n openai/tools/add-venv.* \n \n The script executed in the previous step (cmd for Windows, sh for Linux/Mac) to create all Python virtual environments required for this tutorial. \n \n .venv/openai-webjob/ \n \n A virtual environment specifically used for training models (i.e., calculating embedding vectors indeed). \n \n openai/webjob/requirements.txt \n \n The list of packages (with exact versions) required for the openai-webjob virtual environment. \n \n .venv/openai/ \n \n A virtual environment specifically used for the Flask application, enabling API endpoint access for querying predictions (i.e., suggestion). \n \n openai/requirements.txt \n \n The list of packages (with exact versions) required for the openai virtual environment. \n \n openai/ \n \n The main folder for this tutorial. \n \n openai/tools/arm-template.json \n \n The ARM template to setup all the Azure resources related to this tutorial, including an App Service Plan, a Web App, and a Storage Account. \n \n openai/tools/create-folder.* \n \n A script to create all directories required for this tutorial in the File Share, including train, model, and test. \n \n openai/tools/download-sample-training-set.* \n \n A script to download a sample training set from News-Headlines-Dataset-For-Sarcasm-Detection, containing headlines data from TheOnion and HuffPost, into the train directory of the File Share. \n \n openai/webjob/cal_embeddings.py \n \n A script for calculating embedding vectors from headlines. It loads the training set, applies the transformation on OpenAI API, and saves the embedding vectors in the model directory of the File Share. \n \n openai/App_Data/jobs/triggered/cal-embeddings/cal_embeddings.sh \n \n A shell script for Azure App Service web jobs. It activates the openai-webjob virtual environment and starts the cal_embeddings.py script. \n \n openai/api/app.py \n \n Code for the Flask application, including routes, port configuration, input parsing, vectors loading, predictions, and output generation. \n \n openai/start.sh \n \n A script executed after deployment (as specified in the ARM template startup command I will introduce it later). It sets up the virtual environment and starts the Flask application to handle web requests. \n \n   \n ARM Template \n We need to create the following resources or services: \n \n   \n \n Manual Creation Required \n \n Resource/Service \n \n App Service Plan \n \n No \n \n Resource (plan) \n \n App Service \n \n Yes \n \n Resource (app) \n \n Storage Account \n \n Yes \n \n Resource (storageAccount) \n \n File Share \n \n Yes \n \n Service \n \n Let’s take a look at the openai/tools/arm-template.json file. Refer to the configuration section for all the resources. \n \n Since most of the configuration values don’t require changes, I’ve placed them in the variables section of the ARM template rather than the parameters section. This helps keep the configuration simpler. However, I’d still like to briefly explain some of the more critical settings. \n   \n As you can see, I’ve adopted a camelCase naming convention, which combines the [Resource Type] with [Setting Name and Hierarchy]. This makes it easier to understand where each setting will be used. The configurations in the diagram are sorted by resource name, but the following list is categorized by functionality for better clarity. \n \n Configuration Name \n \n Value \n \n Purpose \n \n storageAccountFileShareName \n \n data-and-model \n \n [Purpose 1: Link File Share to Web App] Use this fixed name for File Share \n \n storageAccountFileShareShareQuota \n \n 5120 \n \n [Purpose 1: Link File Share to Web App] The value is in GB \n \n storageAccountFileShareEnabledProtocols \n \n SMB \n \n [Purpose 1: Link File Share to Web App] \n \n appSiteConfigAzureStorageAccountsType \n \n AzureFiles \n \n [Purpose 1: Link File Share to Web App] \n \n appSiteConfigAzureStorageAccountsProtocol \n \n Smb \n \n [Purpose 1: Link File Share to Web App] \n \n planKind \n \n linux \n \n [Purpose 2: Specify platform and stack runtime] \n Select Linux (default if Python stack is chosen) \n \n planSkuTier \n \n Premium0V3 \n \n [Purpose 2: Specify platform and stack runtime] Choose at least Premium Plan to ensure enough memory for your AI workloads \n \n planSkuName \n \n P0v3 \n \n [Purpose 2: Specify platform and stack runtime] Same as above \n \n appKind \n \n app,linux \n \n [Purpose 2: Specify platform and stack runtime] \n Same as above \n \n appSiteConfigLinuxFxVersion \n \n PYTHON|3.9 \n \n [Purpose 2: Specify platform and stack runtime] Select Python 3.9 to avoid dependency issues \n \n appSiteConfigAppSettingsWEBSITES_CONTAINER_START_TIME_LIMIT \n \n 600 \n \n [Purpose 3: Deploying] \n The value is in seconds, ensuring the Startup Command can continue execution beyond the default timeout of 230 seconds. This tutorial’s Startup Command typically takes around 300 seconds, so setting it to 600 seconds provides a safety margin and accommodates future project expansion (e.g., adding more packages) \n \n appSiteConfigAppCommandLine \n \n [ -f /home/site/wwwroot/start.sh ] && bash /home/site/wwwroot/start.sh || GUNICORN_CMD_ARGS=\\\"--timeout 600 --access-logfile '-' --error-logfile '-' -c /opt/startup/gunicorn.conf.py --chdir=/opt/defaultsite\\\" gunicorn application:app \n \n [Purpose 3: Deploying] \n This is the Startup Command, which can be break down into 3 parts: \n \n First (-f /home/site/wwwroot/start.sh): Checks whether start.sh exists. This is used to determine whether the app is in its initial state (just created) or has already been deployed. \n Second (bash /home/site/wwwroot/start.sh): If the file exists, it means the app has already been deployed. The start.sh script will be executed, which installs the necessary packages and starts the Flask application. \n Third (GUNICORN_CMD_ARGS=\\\"--timeout 600 --access-logfile '-' --error-logfile '-' -c /opt/startup/gunicorn.conf.py --chdir=/opt/defaultsite\\\" gunicorn application:app): If the file does not exist, the command falls back to the default HTTP server (gunicorn) to start the web app. \n \n Since the command is enclosed in double quotes within the ARM template, during actual execution, replace \\\" with \" \n \n appSiteConfigAppSettingsSCM_DO_BUILD_DURING_DEPLOYMENT \n \n false \n \n [Purpose 3: Deploying] \n Since we have already defined the handling for different virtual environments in start.sh, we do not need to initiate the default build process of the Web App \n \n appSiteConfigAppSettingsWEBSITES_ENABLE_APP_SERVICE_STORAGE \n \n true \n \n [Purpose 4: Webjobs] \n This setting is required to enable the App Service storage feature, which is necessary for using web jobs (e.g., for model training) \n \n storageAccountPropertiesAllowSharedKeyAccess \n \n true \n \n [Purpose 5: Troubleshooting] This setting is enabled by default. The reason for highlighting it is that certain enterprise IT policies may enforce changes to this configuration after a period, potentially causing a series of issues. For more details, please refer to the Troubleshooting section below. \n \n   \n Return to bash terminal and execute the following commands (their purpose has been described earlier). \n # Please change <ResourceGroupName> to your prefer name, for example: azure-appservice-ai # Please change <RegionName> to your prefer region, for example: eastus2 # Please change <ResourcesPrefixName> to your prefer naming pattern, for example: openai-arm (it will create openai-arm-asp as App Service Plan, openai-arm-app for web app, and openaiarmsa for Storage Account) az group create --name <ResourceGroupName> --location <RegionName> az deployment group create --resource-group <ResourceGroupName> --template-file ./openai/tools/arm-template.json --parameters resourcePrefix=<ResourcesPrefixName> \n If you are using a Windows platform, use the following alternative PowerShell commands instead: \n # Please change <ResourceGroupName> to your prefer name, for example: azure-appservice-ai # Please change <RegionName> to your prefer region, for example: eastus2 # Please change <ResourcesPrefixName> to your prefer naming pattern, for example: openai-arm (it will create openai-arm-asp as App Service Plan, openai-arm-app for web app, and openaiarmsa for Storage Account) az group create --name <ResourceGroupName> --location <RegionName> az deployment group create --resource-group <ResourceGroupName> --template-file .\\openai\\tools\\arm-template.json --parameters resourcePrefix=<ResourcesPrefixName> \n   \n After execution, please copy the output section containing 3 key-value pairs from the result like this. \n \n   \n Return to bash terminal and execute the following commands: \n # Please setup 3 variables you've got from the previous step OUTPUT_STORAGE_NAME=\"<outputStorageName>\" OUTPUT_STORAGE_KEY=\"<outputStorageKey>\" OUTPUT_SHARE_NAME=\"<outputShareName>\" sudo mkdir -p /mnt/$OUTPUT_SHARE_NAME if [ ! -d \"/etc/smbcredentials\" ]; then sudo mkdir /etc/smbcredentials fi CREDENTIALS_FILE=\"/etc/smbcredentials/$OUTPUT_STORAGE_NAME.cred\" if [ ! -f \"$CREDENTIALS_FILE\" ]; then sudo bash -c \"echo \\\"username=$OUTPUT_STORAGE_NAME\\\" >> $CREDENTIALS_FILE\" sudo bash -c \"echo \\\"password=$OUTPUT_STORAGE_KEY\\\" >> $CREDENTIALS_FILE\" fi sudo chmod 600 $CREDENTIALS_FILE sudo bash -c \"echo \\\"//$OUTPUT_STORAGE_NAME.file.core.windows.net/$OUTPUT_SHARE_NAME /mnt/$OUTPUT_SHARE_NAME cifs nofail,credentials=$CREDENTIALS_FILE,dir_mode=0777,file_mode=0777,serverino,nosharesock,actimeo=30\\\" >> /etc/fstab\" sudo mount -t cifs //$OUTPUT_STORAGE_NAME.file.core.windows.net/$OUTPUT_SHARE_NAME /mnt/$OUTPUT_SHARE_NAME -o credentials=$CREDENTIALS_FILE,dir_mode=0777,file_mode=0777,serverino,nosharesock,actimeo=30 \n Or you could simply go to Azure Portal, navigate to the File Share you just created, and refer to the diagram below to copy the required command. You can choose Windows or Mac if you are using such OS in your dev environment. \n \n   \n After executing the command, the network drive will be successfully mounted. You can use df to verify, as illustrated in the diagram. \n \n   \n   \n ARM Template From Azure Portal \n In addition to using az cli to invoke ARM Templates, if the JSON file is hosted on a public network URL, you can also load its configuration directly into the Azure Portal by following the method described in the article [Deploy to Azure button - Azure Resource Manager]. This is my example. \n Click Me \n   \n After filling in all the required information, click Create. \n \n   \n Once the creation process is complete, click Outputs on the left menu to retrieve the connection information for the File Share. \n \n   \n 4. Running Locally \n Training Models and Training Data \n In the next steps, you will need to use OpenAI services. Please ensure that you have registered as a member and added credits to your account (Billing overview - OpenAI API). For this example, adding $10 USD will be sufficient. Additionally, you will need to generate a new API key (API keys - OpenAI API), you may choose to create a project as well for future project organization, depending on your needs (Projects - OpenAI API). \n \n   \n After getting the API key, create a text file named apikey.txt in the openai/tools/ folder. Paste the key you just copied into the file and save it. \n \n   \n Return to bash terminal and execute the following commands (their purpose has been described earlier). \n source .venv/openai-webjob/bin/activate bash ./openai/tools/create-folder.sh bash ./openai/tools/download-sample-training-set.sh python ./openai/webjob/cal_embeddings.py --sampling_ratio 0.002 \n If you are using a Windows platform, use the following alternative PowerShell commands instead: \n .\\.venv\\openai-webjob\\Scripts\\Activate.ps1 .\\openai\\tools\\create-folder.cmd .\\openai\\tools\\download-sample-training-set.cmd python .\\openai\\webjob\\cal_embeddings.py --sampling_ratio 0.002 \n   \n After execution, the File Share will now include the following directories and files. \n \n   \n Let’s take a brief detour to examine the structure of the training data downloaded from the GitHub. \n \n   \n The right side of the image explains each field of the data. This dataset was originally used to detect whether news headlines contain sarcasm. However, I am repurposing it for another application. In this example, I will use the \"headline\" field to create embeddings. The left side displays the raw data, where each line is a standalone JSON string containing the necessary fields. \n   \n In the code, I first extract the \"headline\" field from each record and send it to OpenAI to compute the embedding vector for the text. This embedding represents the position of the text in a semantic space (akin to coordinates in a multi-dimensional space). After the computation, I obtain an embedding vector for each headline. Moving forward, I will refer to these simply as embeddings. \n   \n By the way, the sampling_ratio parameter in the command is something I configured to speed up the training process. The original dataset contains nearly 30,000 records, which would result in a training time of around 8 hours. To simplify the tutorial, you can specify a relatively low sampling_ratio value (ranging from 0 to 1, representing 0% to 100% sampling from the original records). For example, a value of 0.01 corresponds to a 1% sample, allowing you to accelerate the experiment. \n   \n In this semantic space, vectors that are closer to each other often have similar values, which corresponds to similar meanings. In this context, the distance between vectors will serve as our metric to evaluate the semantic similarity between pieces of text. For this, we will use a method called cosine similarity. \n   \n In the subsequent tutorial, we will construct some test texts. These test texts will also be converted into embeddings using the same method. Each test embedding will then be compared against the previously computed headline embeddings. The comparison will identify the nearest headline embeddings in the multi-dimensional vector space, and their original text will be returned. \n   \n Additionally, we will leverage OpenAI's well-known generative AI capabilities to provide a textual explanation. This explanation will describe why the constructed test text is related to the recommended headline. \n Predicting with the Model \n Return to terminal and execute the following commands. First, deactivate the virtual environment used for calculating the embeddings, then activate the virtual environment for the Flask application, and finally, start the Flask app. \n   \n Commands for Linux or Mac: \n deactivate source .venv/openai/bin/activate python ./openai/api/app.py \n Commands for Windows: \n deactivate .\\.venv\\openai\\Scripts\\Activate.ps1 python .\\openai\\api\\app.py \n   \n When you see a screen similar to the following, it means the server has started successfully. Press Ctrl+C to stop the server if needed. \n \n   \n Before conducting the actual test, let’s construct some sample query data: \n education \n Next, open a terminal and use the following curl commands to send requests to the app: \n curl -X GET http://127.0.0.1:8000/api/detect?text=education \n You should see the calculation results, confirming that the embeddings and Gen AI is working as expected. \n   \n PS: Your results may differ from mine due to variations in the sampling of your training dataset compared to mine. Additionally, OpenAI's generative content can produce different outputs depending on the timing and context. Please keep this in mind. \n 5. Publishing the Project to Azure \n Return to terminal and execute the following commands. \n   \n Commands for Linux or Mac: \n # Please change <resourcegroup_name> and <webapp_name> to your own # Create the Zip file from project zip -r openai/app.zip openai/* # Deploy the App az webapp deploy --resource-group <resourcegroup_name> --name <webapp_name> --src-path openai/app.zip --type zip # Delete the Zip file rm openai/app.zip \n Commands for Windows: \n # Please change <resourcegroup_name> and <webapp_name> to your own # Create the Zip file from project Compress-Archive -Path openai\\* -DestinationPath openai\\app.zip # Deploy the App az webapp deploy --resource-group <resourcegroup_name> --name <webapp_name> --src-path openai\\app.zip --type zip # Delete the Zip file del openai\\app.zip \n   \n PS: WebJobs follow the directory structure of App_Data/jobs/triggered/<webjob_name>/. As a result, once the Web App is deployed, the WebJob is automatically deployed along with it, requiring no additional configuration. \n 6. Running on Azure Web App \n Training the Model \n Return to terminal and execute the following commands to invoke the WebJobs. \n Commands for Linux or Mac: \n # Please change <subscription_id> <resourcegroup_name> and <webapp_name> to your own token=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv) ; curl -X POST -H \"Authorization: Bearer $token\" -H \"Content-Type: application/json\" -d '{}' \"https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourcegroup_name>/providers/Microsoft.Web/sites/<webapp_name>/triggeredwebjobs/cal-embeddings/run?api-version=2024-04-01\" \n Commands for Windows: \n # Please change <subscription_id> <resourcegroup_name> and <webapp_name> to your own $token=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv) ; Invoke-RestMethod -Uri \"https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourcegroup_name>/providers/Microsoft.Web/sites/<webapp_name>/triggeredwebjobs/cal-embeddings/run?api-version=2024-04-01\" -Headers @{Authorization = \"Bearer $token\"; \"Content-type\" = \"application/json\"} -Method POST -Body '{}' \n   \n You could see the training status by execute the following commands. \n Commands for Linux or Mac: \n # Please change <subscription_id> <resourcegroup_name> and <webapp_name> to your own token=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv) ; response=$(curl -s -H \"Authorization: Bearer $token\" \"https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourcegroup_name>/providers/Microsoft.Web/sites/<webapp_name>/webjobs?api-version=2024-04-01\") ; echo \"$response\" | jq \n Commands for Windows: \n # Please change <subscription_id> <resourcegroup_name> and <webapp_name> to your own $token=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv); $response = Invoke-RestMethod -Uri \"https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourcegroup_name>/providers/Microsoft.Web/sites/<webapp_name>/webjobs?api-version=2024-04-01\" -Headers @{Authorization = \"Bearer $token\"} -Method GET ; $response | ConvertTo-Json -Depth 10 \n \n Processing \n \n Complete \n \n   \n \n   \n   \n \n   \n \n   \n   \n \n   \n And you can get the latest detail log by execute the following commands. \n   \n Commands for Linux or Mac: \n # Please change <subscription_id> <resourcegroup_name> and <webapp_name> to your own token=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv) ; history_id=$(az webapp webjob triggered log --resource-group <resourcegroup_name> --name <webapp_name> --webjob-name cal-embeddings --query \"[0].id\" -o tsv | sed 's|.*/history/||') ; response=$(curl -X GET -H \"Authorization: Bearer $token\" -H \"Content-Type: application/json\" \"https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourcegroup_name>/providers/Microsoft.Web/sites/<webapp_name>/triggeredwebjobs/cal-embeddings/history/$history_id/?api-version=2024-04-01\") ; log_url=$(echo \"$response\" | jq -r '.properties.output_url') ; curl -X GET -H \"Authorization: Bearer $token\" \"$log_url\" \n Commands for Windows: \n # Please change <subscription_id> <resourcegroup_name> and <webapp_name> to your own $token = az account get-access-token --resource https://management.azure.com --query accessToken -o tsv ; $history_id = az webapp webjob triggered log --resource-group <resourcegroup_name> --name <webapp_name> --webjob-name cal-embeddings --query \"[0].id\" -o tsv | ForEach-Object { ($_ -split \"/history/\")[-1] } ; $response = Invoke-RestMethod -Uri \"https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourcegroup_name>/providers/Microsoft.Web/sites/<webapp_name>/triggeredwebjobs/cal-embeddings/history/$history_id/?api-version=2024-04-01\" -Headers @{ Authorization = \"Bearer $token\" } -Method GET ; $log_url = $response.properties.output_url ; Invoke-RestMethod -Uri $log_url -Headers @{ Authorization = \"Bearer $token\" } -Method GET \n   \n Once you see the report in the Logs, it indicates that the embeddings calculation is complete, and the Flask app is ready for predictions. \n   \n You can also find the newly calculated embeddings in the File Share mounted in your local environment. \n \n   \n   \n Using the Model for Prediction \n Just like in local testing, open a bash terminal and use the following curl commands to send requests to the app: \n # Please change <webapp_name> to your own curl -X GET https://<webapp_name>.azurewebsites.net/api/detect?text=education \n   \n As with the local environment, you should see the expected results. \n \n   \n 7. Troubleshooting \n Startup Command Issue \n \n Symptom: Without any code changes and when the app was previously functioning, updating the Startup Command causes the app to stop working. \n The related default_docker.log shows multiple attempts to run the container without errors in a short time, but the container does not respond on port 8000 as seen in docker.log. \n \n Cause: Since Linux Web Apps actually run in containers, the final command in the Startup Command must function similarly to the CMD instruction in a Dockerfile. CMD [\"/usr/sbin/sshd\", \"-D\", \"-o\", \"ListenAddress=0.0.0.0\"] \n This command must ensure it runs in the foreground (i.e., not in daemon mode) and cannot exit the process unless manually interrupted. \n \n Resolution: Check the final command in the Startup Command to ensure it does not include a daemon execution mode. Alternatively, use the Web SSH interface to execute and verify these commands directly. \n \n App Becomes Unresponsive After a Period \n \n Symptom: An app that runs normally becomes unresponsive after some time. Both the front-end webpage and the Kudu page display an \"Application Error,\" and the deployment log shows \"Too many requests.\" Additionally, the local environment cannot connect to the associated File Share. \n Cause: Clicking on \"diagnostic resources\" in the initial error screen provides more detailed error information. \n In this example, the issue is caused by internal enterprise Policies or Automations (e.g., enterprise applications) that periodically or randomly scan storage account settings created by employees. If the settings are deemed non-compliant with security standards, they are automatically adjusted. \n For instance, the allowSharedKeyAccess parameter may be forcibly set to false, preventing both the Web App and the local development environment from connecting to the File Share under the Storage Account. Modification history for such settings can be checked via the Activity Log of the Storage Account (note that only the last 90 days of data are retained). \n \n Resolution: The proper approach is to work offline with the enterprise IT team to coordinate and request the necessary permissions.\n As a temporary workaround, modify the affected settings to Enable during testing periods and revert them to Disabled afterward. You can find the setting for allowSharedKeyAccess here. \n \n Note: Azure Storage Mount currently does not support access via Managed Identity. \n \n \n az cli command for Linux webjobs fail \n \n Symptom: Got \"Operation returned an invalid status 'Unauthorized'\" message from different platforms even in Azure CloudShell with latest az version \n Cause: After using \"--debug --verbose\" from the command I can see the actual error occurred on which REST API, for example, I'm using this command (az webapp webjob triggered): az webapp webjob triggered list --resource-group azure-appservice-ai --name openai-arm-app --debug --verbose \n  Which represent that the operation has invoked under this API: \n /Microsoft.Web/sites/{app_name}/triggeredwebjobs (Web Apps - List Triggered Web Jobs) \n After I directly test that API from the official doc, I still get such the error, which means this preview feature is still under construction, and we cannot use it currently. \n \n   \n \n Resolution: I found a related API endpoint via Azure Portal: \n /Microsoft.Web/sites/{app_name}/webjobs (Web Apps - List Web Jobs) \n After I directly test that API from the official doc, I can get the trigger list now. \n \n So I have modified the original command: \n az webapp webjob triggered list --resource-group azure-appservice-ai --name openai-arm-app \n  To the following command (please note the differences between Linux/Mac and Windows commands). \n Make sure to replace <subscription_id>, <resourcegroup_name>, and <webapp_name> with your specific values. \n Commands for Linux or Mac: \n token=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv) ; response=$(curl -s -H \"Authorization: Bearer $token\" \"https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourcegroup_name>/providers/Microsoft.Web/sites/<webapp_name>/webjobs?api-version=2024-04-01\") ; echo \"$response\" | jq \n Commands for Windows: \n $token=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv); $response = Invoke-RestMethod -Uri \"https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourcegroup_name>/providers/Microsoft.Web/sites/<webapp_name>/webjobs?api-version=2024-04-01\" -Headers @{Authorization = \"Bearer $token\"} -Method GET ; $response | ConvertTo-Json -Depth 10 \n For \"run\" commands, due to the same issue when invoking the problematic API, so I also modify the operation. \n Commands for Linux or Mac: \n token=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv) ; curl -X POST -H \"Authorization: Bearer $token\" -H \"Content-Type: application/json\" -d '{}' \"https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourcegroup_name>/providers/Microsoft.Web/sites/<webapp_name>/triggeredwebjobs/cal-embeddings/run?api-version=2024-04-01\" \n Commands for Windows: \n $token=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv) ; Invoke-RestMethod -Uri \"https://management.azure.com/subscriptions/029b4739-1f55-4cab-bf84-a9393f8ac8fe/resourceGroups/azure-appservice-ai/providers/Microsoft.Web/sites/openai-arm-app/triggeredwebjobs/cal-embeddings/run?api-version=2024-04-01\" -Headers @{Authorization = \"Bearer $token\"; \"Content-type\" = \"application/json\"} -Method POST -Body '{}' \n   \n \n \n Others \n Using Scikit-learn on Azure Web App \n 8. Conclusion \n Beyond simple embedding vector calculations, OpenAI's most notable strength is generative AI. You can provide instructions to the GPT model through natural language (as a prompt), clearly specifying the format you need in the instruction. You can then parse the returned content easily. While PaaS products are not ideal for heavy vector calculations, they are well-suited for acting as intermediaries to forward commands to generative AI. These outputs can even be used for various applications, such as patent infringement detection, plagiarism detection in research papers, or trending news analysis. \n   \n I believe that in the future, we will see more similar applications on Azure Web Apps. \n 9. References \n Overview - OpenAI API \n News-Headlines-Dataset-For-Sarcasm-Detection \n Quickstart: Deploy a Python (Django, Flask, or FastAPI) web app to Azure - Azure App Service \n Configure a custom startup file for Python apps on Azure App Service on Linux - Python on Azure \n Mount Azure Storage as a local share - Azure App Service \n Deploy to Azure button - Azure Resource Manager \n Using Scikit-learn on Azure Web App ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"33019","kudosSumWeight":0,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWxzR2dGRw?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTg2OEtiRQ?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LXZMZ3gzcw?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU1RbUNCSw?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTAwUGJHVg?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU0yVnFjaA?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDc","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU02VExIcg?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDg","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVQ1QkNuOQ?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDk","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVZZZGdHWg?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEw","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LUR2dzJSRQ?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEx","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWVKN2haVQ?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEy","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWh4SlhNbA?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEz","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LU5aaDFQNQ?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE0","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTFBYkVKQw?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE1","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LXk4SzF1WQ?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE2","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LXc0UzJ4Rg?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE3","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTN5ZHdsNQ?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE4","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTE3VFBsbA?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE5","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LUtKZndsZQ?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIw","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTRXRmplVg?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIx","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVl6WWlFdw?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIy","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LTJDbTZSYw?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIz","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LUtURjVTZg?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI0","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LVBpd2htbw?revision=10\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI1","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzM0OTg1LWtZNjBwQw?revision=10\"}"}}],"totalCount":32,"pageInfo":{"__typename":"PageInfo","hasNextPage":true,"endCursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI1","hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:4360288":{"__typename":"Conversation","id":"conversation:4360288","topic":{"__typename":"BlogTopicMessage","uid":4360288},"lastPostingActivityTime":"2024-12-26T03:17:46.087-08:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXFMdmFJUQ?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXFMdmFJUQ?revision=5","title":"image.png","associationType":"BODY","width":2151,"height":110,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LVBBd2dESw?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LVBBd2dESw?revision=5","title":"image.png","associationType":"BODY","width":1580,"height":842,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTZsTnlJdw?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTZsTnlJdw?revision=5","title":"image.png","associationType":"BODY","width":1556,"height":1189,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWNRQ1dlZQ?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWNRQ1dlZQ?revision=5","title":"clipboard_image-1-1735010182483.png","associationType":"BODY","width":958,"height":567,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTFhWkdCWg?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTFhWkdCWg?revision=5","title":"clipboard_image-2-1735010226475.png","associationType":"BODY","width":1114,"height":778,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LU5aZWhpSQ?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LU5aZWhpSQ?revision=5","title":"clipboard_image-3-1735010261471.png","associationType":"BODY","width":1680,"height":828,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXpIdUVxVw?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXpIdUVxVw?revision=5","title":"clipboard_image-4-1735010376249.png","associationType":"BODY","width":1868,"height":520,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXVSSmg5bw?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXVSSmg5bw?revision=5","title":"clipboard_image-5-1735010466215.png","associationType":"BODY","width":1824,"height":926,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTBwcUFjWg?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTBwcUFjWg?revision=5","title":"clipboard_image-6-1735010558024.png","associationType":"BODY","width":1171,"height":611,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LVRueWRnbQ?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LVRueWRnbQ?revision=5","title":"clipboard_image-7-1735010724582.png","associationType":"BODY","width":1773,"height":1197,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LThSZ09aOA?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LThSZ09aOA?revision=5","title":"clipboard_image-8-1735010724580.png","associationType":"BODY","width":1550,"height":603,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWRBZVlkeA?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWRBZVlkeA?revision=5","title":"clipboard_image-9-1735010724581.png","associationType":"BODY","width":1778,"height":1131,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWZGT2hvdQ?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWZGT2hvdQ?revision=5","title":"clipboard_image-10-1735010724581.png","associationType":"BODY","width":1752,"height":1125,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTVCZ2o2dA?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTVCZ2o2dA?revision=5","title":"clipboard_image-11-1735010797003.png","associationType":"BODY","width":1707,"height":882,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWZBS3h2bA?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWZBS3h2bA?revision=5","title":"clipboard_image-12-1735010797003.png","associationType":"BODY","width":1304,"height":1464,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LURmR0NWSw?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LURmR0NWSw?revision=5","title":"clipboard_image-13-1735010797004.png","associationType":"BODY","width":2094,"height":1309,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LUhuMkI2eg?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LUhuMkI2eg?revision=5","title":"clipboard_image-1-1735211290612.png","associationType":"BODY","width":2094,"height":1321,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWtGTjVHUA?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWtGTjVHUA?revision=5","title":"clipboard_image-2-1735211290612.png","associationType":"BODY","width":1746,"height":1150,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTUySGpEOA?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTUySGpEOA?revision=5","title":"image.png","associationType":"BODY","width":1727,"height":1158,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LVdnMDJ3Ng?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LVdnMDJ3Ng?revision=5","title":"image.png","associationType":"BODY","width":1373,"height":100,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LUR2cDd1aQ?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LUR2cDd1aQ?revision=5","title":"image.png","associationType":"BODY","width":1712,"height":200,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXdsUVNlaQ?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXdsUVNlaQ?revision=5","title":"image.png","associationType":"BODY","width":2094,"height":944,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXpEeDFMag?revision=5\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXpEeDFMag?revision=5","title":"image.png","associationType":"BODY","width":1706,"height":217,"altText":""},"BlogTopicMessage:message:4360288":{"__typename":"BlogTopicMessage","subject":"Connection Between Web App and O365 Resources: Using SharePoint as an Example","conversation":{"__ref":"Conversation:conversation:4360288"},"id":"message:4360288","revisionNum":5,"uid":4360288,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:1357822"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"Microsoft Entra enforced MFA for all user login processes in late 2024. This change has caused some Web Apps using delegated permissions to fail in acquiring access tokens, thereby interrupting communication with other resources.","metrics":{"__typename":"MessageMetrics","views":557},"postTime":"2024-12-23T19:28:27.568-08:00","lastPublishTime":"2024-12-26T03:17:46.087-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" TOC \n \n Introduction \n \n [not recommended] Application permission \n \n [not recommended] Delegate permission with Device Code Flow \n Managed Identity \n Multi-Tenant App Registration \n Restrict Resources for Application permission \n References \n \n   \n Introduction \n In late 2024, Microsoft Entra enforced MFA (Multi-Factor Authentication) for all user login processes. This change has caused some Web Apps using delegated permissions to fail in acquiring access tokens, thereby interrupting communication with O365 resources. This tutorial will present various alternative solutions tailored to different business requirements. \n We will use a Linux Python Web App as an example in the following sections. \n [not recommended] Application permission \n Traditionally, using delegated permissions has the advantages of being convenient, quick, and straightforward, without being limited by whether the Web App and Target resources (e.g., SharePoint) are in the same tenant. This is because it leverages the user identity in the SharePoint tenant as the login user. \n However, its drawbacks are quite evident—it is not secure. Delegated permissions are not designed for automated processes (i.e., Web Apps), and if the associated connection string (i.e., app secret) is obtained by a malicious user, it can be directly exploited. \n Against this backdrop, Microsoft Entra enforced MFA for all user login processes in late 2024. Since delegated permissions rely on user-based authentication, they are also impacted. Specifically, if your automated processes originally used delegated permissions to interact with other resources, they are likely to be interrupted by errors similar to the following in recent times. \n AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access '00000003-0000-0000-c000-000000000000' \n   \n The root cause lies in the choice of permission type. While delegated permissions can technically be used for automated processes, there is a more appropriate option—application permissions, which are specifically designed for use in automated workflows. \n Therefore, when facing such issues, the quickest solution is to create a set of application permissions, align their settings with your previous delegated permissions, and then update your code to use the new app ID and secret to interact with the target resource. \n This method resolves the issue caused by the mandatory MFA process interruption. However, it is still not entirely secure, as the app secret, if obtained by a malicious user, can be exploited directly. Nonetheless, it serves as a temporary solution while planning for a large-scale modification or refactor of your existing system. \n [not recommended] Delegate permission with Device Code Flow \n Similarly, here's another temporary solution. The advantage of this approach is that you don't even need to create a new set of application permissions. Instead, you can retain the existing delegated permissions and resolve the issue by integrating Device Code Flow. Let's see how this can be achieved. \n First, navigate to Microsoft Entra > App Registration > Your Application > Authentication, and enable \"Allow public client flows\". \n \n   \n Next, modify your code to implement the following method to acquire the token. Replace [YOUR_TENANT_ID] and [YOUR_APPLICATION_ID] with your own values. \n import os, atexit, msal, sys\n\ndef get_access_token_device():\n cache_filename = os.path.join(\n os.getenv(\"XDG_RUNTIME_DIR\", \"\"), \"my_cache.bin\"\n )\n cache = msal.SerializableTokenCache()\n if os.path.exists(cache_filename):\n cache.deserialize(open(cache_filename, \"r\").read())\n atexit.register(lambda:\n open(cache_filename, \"w\").write(cache.serialize())\n if cache.has_state_changed else None\n )\n config = {\n \"authority\": \"https://login.microsoftonline.com/[YOUR_TENANT_ID]\",\n \"client_id\": \"[YOUR_APPLICATIOM_ID]\",\n \"scope\": [\"https://graph.microsoft.com/.default\"]\n }\n app = msal.PublicClientApplication(\n config[\"client_id\"], authority=config[\"authority\"],\n token_cache=cache,\n )\n result = None\n accounts = app.get_accounts()\n if accounts:\n print(\"Pick the account you want to use to proceed:\")\n for a in accounts:\n print(a[\"username\"])\n chosen = accounts[0]\n result = app.acquire_token_silent([\"User.Read\"], account=chosen)\n if not result:\n flow = app.initiate_device_flow(scopes=config[\"scope\"])\n print(flow[\"message\"])\n sys.stdout.flush()\n result = app.acquire_token_by_device_flow(flow)\n if \"access_token\" in result:\n access_token = result[\"access_token\"]\n return access_token\n else:\n error = result.get(\"error\")\n if error == \"invalid_client\":\n print(\"Invalid client ID.Please check your Azure AD application configuration\")\n else:\n print(error)\n \n   \n Demonstrating the Process \n \n \n Before acquiring the token for the first time, there is no cache file named my_cache.bin in your project directory. \n Start the test code, which includes obtaining the token and interacting with the corresponding service (e.g., SharePoint) using the token. \n Since this is the first use, the system will prompt you to manually visit https://microsoft.com/devicelogin and input the provided code. Once the manual process is complete, the system will obtain the token and execute the workflow. \n After acquiring the token, the cache file my_cache.bin will appear in your project directory. This file contains the access_token and refresh_token. \n For subsequent processes, whether triggered manually or automatically, the system will no longer prompt for manual login. \n \n   \n The cached token has a validity period of approximately one hour, which may seem insufficient. However, the acquire_token_silent function in the program will automatically use the refresh token to renew the access token and update the cache. Therefore, as long as an internal script or web job is triggered at least once every hour, the token can theoretically be used continuously. \n Managed Identity \n Using Managed Identity to enable interaction between an Azure Web App and other resources is currently the best solution. It ensures that no sensitive information (e.g., app secrets) is included in the code and guarantees that only the current Web App can use this authentication method. Therefore, it meets both convenience and security requirements for production environments. \n Let’s take a detailed look at how to set it up. \n   \n Step 1: Setup Managed Identity \n You will get an Object ID for further use. \n \n   \n Step 2: Enterprise Application for Managed Identity \n Your Managed Identity will generate a corresponding Enterprise Application in Microsoft Entra. However, unlike App Registration, where permissions can be assigned directly via the Azure Portal, Enterprise Application permissions must be configured through commands. \n \n   \n Step 3: Log in to Azure via CloudShell \n Use your account to access Azure Portal, open a CloudShell, and input the following command. This step will require you to log in with your credentials using the displayed code: \n Connect-MgGraph -Scopes \"Application.ReadWrite.All\", \"AppRoleAssignment.ReadWrite.All\" \n Continue by inputting the following command to target the Enterprise Application corresponding to your Managed Identity that requires permission assignment: \n $PrincipalId = \"<Your web app managed identity object id>\"\n$ResourceId = (Get-MgServicePrincipal -Filter \"displayName eq 'Microsoft Graph'\" | Select-Object -ExpandProperty Id) \n   \n Step 4: Assign Permissions to the Enterprise Application \n Execute the following commands to assign permissions. Key Points: \n This example assigns all permissions with the prefix Sites.*. However, you can modify this to request only the necessary permissions, such as: \n \n Sites.Selected \n Sites.Read.All \n Sites.ReadWrite.All \n Sites.Manage.All \n Sites.FullControl.All \n \n If you do not wish to assign all permissions, you can change { $_.Value -like \"*Sites.*\" } to the specific permission you need, for example: { $_.Value -like \"*Sites.Selected*\" } \n Each time you modify the permission, you will need to rerun all the commands below. \n $AppRoles = Get-MgServicePrincipal -Filter \"displayName eq 'Microsoft Graph'\" -Property AppRoles |\nSelect -ExpandProperty AppRoles |\nWhere-Object { $_.Value -like \"*Sites.*\" }\n$AppRoles | ForEach-Object {\n $params = @{\n \"PrincipalId\" = $PrincipalId\n \"ResourceId\" = $ResourceId\n \"AppRoleId\" = $_.Id\n }\n New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $PrincipalId -BodyParameter $params\n} \n Step 5: Confirm Assigned Permissions \n If, in Azure Portal, you see a screen similar to this: (Include screenshot or example text for granted permissions) This means that the necessary permissions have been successfully assigned. \n \n   \n Step 6: Retrieve a Token in Python \n In your Python code, you can use the following approach to retrieve the token: \n from azure.identity import ManagedIdentityCredential\n\ndef get_access_token():\n credential = ManagedIdentityCredential()\n token = credential.get_token(\"https://graph.microsoft.com/.default\")\n return token.token \n Important Notes: \n When permissions are assigned or removed in the Enterprise Application, the ManagedIdentityCredential in your Python code caches the token for a while. \n These changes will not take effect immediately. You need to restart your application and wait approximately 10 minutes for the changes to take effect. \n   \n Step 7: Perform Operations with the Token \n Finally, you can use this token to perform the desired operations. Below is an example of creating a file in SharePoint: \n \n You will notice that the uploader’s identity is no longer a person but instead the app itself, indicating that Managed Identity is indeed in effect and functioning properly. \n While this method is effective, it is limited by the inability of Managed Identity to handle cross-tenant resource requests. I will introduce one final method to resolve this limitation. \n   \n Multi-Tenant App Registration \n In many business scenarios, resources are distributed across different tenants. For example, SharePoint is managed by Company (Tenant) B, while the Web App is developed by Company (Tenant) A. Since these resources belong to different tenants, Managed Identity cannot be used in such cases. \n   \n Instead, we need to use a Multi-Tenant Application to resolve the issue. \n   \n The principle of this approach is to utilize an Entra ID Application created by the administrator of Tenant A (i.e., the tenant that owns the Web App) that allows cross-tenant use. This application will be pre-authorized by future user from Tenant B (i.e., the administrator of the tenant that owns SharePoint) to perform operations related to SharePoint. \n   \n It should be noted that the entire configuration process requires the participation of administrators from both tenants to a certain extent. Please refer to the following demonstration. \n   \n This is a sequential tutorial; please note that the execution order cannot be changed. \n   \n Step 1: Actions Required by the Administrator of the Tenant that Owns the Web App \n 1.1. In Microsoft Entra, create an Enterprise Application and select \"Multi-Tenant.\" After creation, note down the Application ID. \n \n   \n 1.2. In App Registration under AAD, locate the previously created application, generate an App Secret, and record it. \n \n   \n 1.3. Still in App Registration, configure the necessary permissions. Choose \"Application Permissions\", then determine which permissions (all starting with \"Sites.\") are needed based on the actual operations your Web App will perform on SharePoint. For demonstration purposes, all permissions are selected here. \n \n   \n Step 2: Actions Required by the Administrator of the Tenant that Owns SharePoint \n 2.1. Use the PowerShell interface to log in to Azure and select the tenant where SharePoint resides. \n az login --allow-no-subscriptions --use-device-code \n   \n 2.2. Add the Multi-Tenant Application to this tenant. \n az ad sp create --id <App id get from step 1.1> \n   \n 2.3. Visit the Azure Portal, go to Enterprise Applications, locate the Multi-Tenant Application added earlier, and navigate to Permissions to grant the permissions specified in step 1.3. \n \n   \n Step 3: Actions Required by the Administrator of the Tenant that Owns the Web App \n 3.1. In your Python code, you can use the following method to obtain an access token: \n from msal import ConfidentialClientApplication\n\ndef get_access_token_cross_tenant():\n tenant_id = \"your-sharepoint-tenant-id\" # Tenant ID where the SharePoint resides (i.e., shown in step 2.1)\n client_id = \"your-multi-tenant-app-client-id\" # App ID created in step 1.1\n client_secret = \"your-app-secret\" # Secret created in step 1.2\n authority = f\"https://login.microsoftonline.com/{tenant_id}\"\n\n app = ConfidentialClientApplication(\n client_id,\n authority=authority,\n client_credential=client_secret\n )\n\n scopes = [\"https://graph.microsoft.com/.default\"]\n token_response = app.acquire_token_for_client(scopes=scopes)\n return token_response.get(\"access_token\")\n \n   \n 3.2. Use this token to perform the required operations. \n Restrict Resources for Application permission \n Application permission, allows authorization under the App’s identity, enabling access to all SharePoint sites within the tenant, which could be overly broad for certain use cases. \n   \n To restrict this permission to access a limited number of SharePoint sites, we need to configure the following settings: \n   \n Actions Required by the Administrator of the Tenant that Owns SharePoint \n \n During the authorization process, only select Sites.Selected. (refer to Step 4 from Managed Identity, and Step 1.3 from Multu-tenant App Registration) \n Subsequently, configure access separately for different SharePoint sites. \n \n   \n During the process, we will create a temporary App Registration to issue an access token, allowing us to assign specific SharePoint sites' read/write permissions to the target Application. Once the permission settings are completed, this App Registration can be deleted. \n \n   \n Refer to the above images, we need to note down the App Registration's object ID and tenant ID. Additionally, we need to create an app secret and grant it the Application permission Sites.FullControl.All. Once the setup is complete, the token can be obtained using the following command. \n $tenantId = \"<Your_Tenant_ID>\"\n$clientId = \"<Your_Temp_AppID>\"\n$clientSecret = \"<Your_Temp_App_Secret>\"\n$scope = \"https://graph.microsoft.com/.default\"\n$url = \"https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token\"\n$body = @{\n grant_type = \"client_credentials\"\n client_id = $clientId\n client_secret = $clientSecret\n scope = $scope\n}\n$response = Invoke-RestMethod -Uri $url -Method Post -Body $body\n$accessToken = $response.access_token \n   \n Before granting the write permission to the target application, even if the Application Permission already has the Sites.Selected scope, an error will still occur. \n \n   \n Checking the current SharePoint site's allowed access list shows that it is empty. \n $headers = @{\n \"Authorization\" = \"Bearer $accessToken\"\n \"Content-Type\" = \"application/json\"\n}\nInvoke-RestMethod -Method Get -Uri \"https://graph.microsoft.com/v1.0/sites/<Your_SharePoint_Site>.sharepoint.com\" -Headers $headers \n   \n Next, we manually add the corresponding Application to the SharePoint site's allowed access list and assign it the write permission. \n $headers = @{\n \"Authorization\" = \"Bearer $accessToken\"\n \"Content-Type\" = \"application/json\"\n}\n$body = @{\n roles = @(\"write\")\n grantedToIdentities = @(\n @{\n application = @{\n id = \"<Your_Target_AppID>\"\n\t\tdisplayName = \"<Your_Target_AppName>\"\n }\n }\n )\n grantedToIdentitiesV2 = @(\n @{\n application = @{\n id = \"<Your_Target_AppID>\"\n\t\tdisplayName = \"<Your_Target_AppName>\"\n }\n }\n )\n} | ConvertTo-Json -Depth 10\nInvoke-RestMethod -Method Post -Uri \"https://graph.microsoft.com/v1.0/sites/<Your_SharePoint_Site>.sharepoint.com/permissions\" -Headers $headers -Body $body \n   \n Rechecking the current SharePoint site's allowed access list confirms the addition. \n \n   \n After that, writing files to the site will succeed, and you could delete the temp App Registration. \n References \n \n Microsoft will require MFA for all Azure users \n Acquire a token to call a web API using device code flow (desktop app) - Microsoft identity platform | Microsoft Learn \n Implement cross-tenant communication by using multitenant applications - Azure Architecture Center \n ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"17358","kudosSumWeight":1,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXFMdmFJUQ?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LVBBd2dESw?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTZsTnlJdw?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWNRQ1dlZQ?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTFhWkdCWg?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LU5aZWhpSQ?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDc","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXpIdUVxVw?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDg","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXVSSmg5bw?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDk","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTBwcUFjWg?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEw","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LVRueWRnbQ?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEx","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LThSZ09aOA?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEy","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWRBZVlkeA?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEz","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWZGT2hvdQ?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE0","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTVCZ2o2dA?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE1","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWZBS3h2bA?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE2","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LURmR0NWSw?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE3","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LUhuMkI2eg?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE4","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LWtGTjVHUA?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE5","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LTUySGpEOA?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIw","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LVdnMDJ3Ng?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIx","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LUR2cDd1aQ?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIy","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXdsUVNlaQ?revision=5\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIz","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MzYwMjg4LXpEeDFMag?revision=5\"}"}}],"totalCount":23,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:4294999":{"__typename":"Conversation","id":"conversation:4294999","topic":{"__typename":"BlogTopicMessage","uid":4294999},"lastPostingActivityTime":"2024-11-21T19:50:14.758-08:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LU5iOVhQaw?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LU5iOVhQaw?revision=12","title":"image.png","associationType":"BODY","width":1073,"height":608,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWtrQWFLaQ?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWtrQWFLaQ?revision=12","title":"image.png","associationType":"BODY","width":735,"height":1279,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWFWRGdwUw?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWFWRGdwUw?revision=12","title":"image.png","associationType":"BODY","width":839,"height":1701,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWMyTlQxNg?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWMyTlQxNg?revision=12","title":"image.png","associationType":"BODY","width":1151,"height":973,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWU5d3R2QQ?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWU5d3R2QQ?revision=12","title":"image.png","associationType":"BODY","width":1493,"height":730,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUtEdzNYMA?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUtEdzNYMA?revision=12","title":"image.png","associationType":"BODY","width":2076,"height":1307,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LVplNHFlUQ?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LVplNHFlUQ?revision=12","title":"image.png","associationType":"BODY","width":1734,"height":928,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LXRPWmxWVQ?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LXRPWmxWVQ?revision=12","title":"image.png","associationType":"BODY","width":1697,"height":722,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTZzWmZYRg?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTZzWmZYRg?revision=12","title":"image.png","associationType":"BODY","width":395,"height":826,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUlSSFJWVw?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUlSSFJWVw?revision=12","title":"image.png","associationType":"BODY","width":937,"height":722,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LW9wNlBlMQ?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LW9wNlBlMQ?revision=12","title":"image.png","associationType":"BODY","width":2487,"height":1406,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUF0aXR4MA?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUF0aXR4MA?revision=12","title":"image.png","associationType":"BODY","width":1899,"height":821,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LXhlNU9KZA?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LXhlNU9KZA?revision=12","title":"image.png","associationType":"BODY","width":2054,"height":404,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUFyV25UTA?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUFyV25UTA?revision=12","title":"image.png","associationType":"BODY","width":1901,"height":1555,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTQxZXVIUg?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTQxZXVIUg?revision=12","title":"clipboard_image-1-1731775947853.png","associationType":"BODY","width":1613,"height":677,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUEyRUo1dw?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUEyRUo1dw?revision=12","title":"clipboard_image-2-1731775947854.png","associationType":"BODY","width":1458,"height":1373,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTZ0bVJMNg?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTZ0bVJMNg?revision=12","title":"image.png","associationType":"BODY","width":1604,"height":645,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTJSTXo0bA?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTJSTXo0bA?revision=12","title":"image.png","associationType":"BODY","width":1614,"height":519,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUVHRXFORQ?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUVHRXFORQ?revision=12","title":"image.png","associationType":"BODY","width":1697,"height":722,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTBjNEt5Qw?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTBjNEt5Qw?revision=12","title":"image.png","associationType":"BODY","width":2449,"height":407,"altText":""},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWV4dVl6Tg?revision=12\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWV4dVl6Tg?revision=12","title":"image.png","associationType":"BODY","width":1439,"height":256,"altText":""},"BlogTopicMessage:message:4294999":{"__typename":"BlogTopicMessage","subject":"Using Scikit-learn on Azure Web App","conversation":{"__ref":"Conversation:conversation:4294999"},"id":"message:4294999","revisionNum":12,"uid":4294999,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:1357822"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"With the increasing adoption of AI frameworks in cloud environments, many users are now exploring ways to deploy Scikit-learn projects on Azure Web Apps. This tutorial provides a step-by-step guide to help you deploy your Scikit-learn project on an Azure Web App, covering everything from resource setup to troubleshooting common issues.","metrics":{"__typename":"MessageMetrics","views":560},"postTime":"2024-11-16T09:17:54.625-08:00","lastPublishTime":"2024-11-21T19:50:14.758-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" TOC \n \n Introduction to Scikit-learn \n System Architecture\n \n Architecture \n Focus of This Tutorial \n \n \n Setup Azure Resources\n \n Web App \n Storage \n \n \n Running Locally\n \n File and Directory Structure \n Training Models and Training Data \n Predicting with the Model \n \n \n Publishing the Project to Azure\n \n Deployment \n Configuration \n \n \n Running on Azure Web App\n \n Training the Model \n Using the Model for Prediction \n \n \n Troubleshooting\n \n Missing Environment Variables After Deployment \n Virtual Environment Resource Lock Issues \n Package Version Dependency Issues \n Default Binding \n Missing System Commands in Restricted Environments \n \n \n Conclusion \n References \n \n   \n 1. Introduction to Scikit-learn \n Scikit-learn is a popular open-source Python library for machine learning, built on NumPy, SciPy, and matplotlib. It offers an efficient and easy-to-use toolkit for data analysis, data mining, and predictive modeling. \n Scikit-learn supports a variety of machine learning algorithms, including classification, regression, clustering, and dimensionality reduction (e.g., SVM, Random Forest, K-means). Its preprocessing utilities handle tasks like scaling, encoding, and missing data imputation. It also provides tools for model evaluation (e.g., accuracy, precision, recall) and pipeline creation, enabling users to chain preprocessing and model training into seamless workflows. \n   \n 2. System Architecture \n Architecture \n \n   \n Development Environment \n \n \n \n \n \n OS:  \n \n Windows 11 \n \n \n \n Version:  \n \n 24H2 \n \n \n \n Python Version: \n \n 3.7.3 \n \n \n \n \n   \n Azure Resources \n \n \n \n \n \n App Service Plan: \n \n SKU - Premium Plan 0 V3 \n \n \n \n App Service: \n \n Platform - Linux (Python 3.9, Version 3.9.19) \n \n \n \n Storage Account: \n \n SKU - General Purpose V2 \n \n \n \n File Share: \n \n No backup plan \n \n \n \n \n Focus of This Tutorial  \n This tutorial walks you through the following stages: \n \n Setting up Azure resources \n Running the project locally \n Publishing the project to Azure \n Running the application on Azure \n Troubleshooting common issues \n \n Each of the mentioned aspects has numerous corresponding tools and solutions. The relevant information for this session is listed in the table below. \n   \n Local OS \n \n \n \n \n \n Windows \n \n \n Linux \n \n \n Mac \n \n \n \n \n V \n \n \n   \n \n \n   \n \n \n \n \n \n   \n How to setup Azure resources \n \n \n \n \n \n Portal (i.e., REST api) \n \n \n ARM \n \n \n Bicep \n \n \n Terraform \n \n \n \n \n V \n \n \n   \n \n \n   \n \n \n   \n \n \n \n \n \n   \n How to deploy project to Azure \n \n \n \n \n \n VSCode \n \n \n CLI \n \n \n Azure DevOps \n \n \n GitHub Action \n \n \n \n \n V \n \n \n   \n \n \n   \n \n \n   \n \n \n \n \n \n   \n 3. Setup Azure Resources \n Web App \n We need to create the following resources or services: \n \n \n \n \n   \n Manual Creation Required \n Resource/Service \n \n \n \n \n App Service Plan \n No \n Resource \n \n \n App Service \n Yes \n Resource \n \n \n Storage Account \n Yes \n Resource \n \n \n File Share \n Yes \n Service \n \n \n \n \n   \n Go to the Azure Portal and create an App Service. \n \n Important configuration: \n \n OS: Select Linux (default if Python stack is chosen). \n Stack: Select Python 3.9 to avoid dependency issues. \n SKU: Choose at least Premium Plan to ensure enough memory for your AI workloads. \n \n Storage \n Create a Storage Account in the Azure Portal. \n \n Create a file share named data-and-model in the Storage Account. \n \n Mount the File Share to the App Service: Use the name data-and-model for consistency with tutorial paths. \n \n At this point, all Azure resources and services have been successfully created. Let’s take a slight detour and mount the recently created File Share to your Windows development environment. \n Navigate to the File Share you just created, and refer to the diagram below to copy the required command. Before copying, please ensure that the drive letter remains set to the default \"Z\" as the sample code in this tutorial will rely on it. \n \n Return to your development environment. Open a PowerShell terminal (do not run it as Administrator) and input the command copied in the previous step, as shown in the diagram. \n \n After executing the command, the network drive will be successfully mounted. You can open File Explorer to verify, as illustrated in the diagram. \n \n   \n 4. Running Locally \n File and Directory Structure \n Please use VSCode to open a PowerShell terminal and enter the following commands: \n git clone https://github.com/theringe/azure-appservice-ai.git\ncd azure-appservice-ai\n.\\scikit-learn\\tools\\add-venv.cmd \n If you are using a Linux or Mac platform, use the following alternative commands instead: \n git clone https://github.com/theringe/azure-appservice-ai.git\ncd azure-appservice-ai\nbash ./scikit-learn/tools/add-venv.sh \n After completing the execution, you should see the following directory structure: \n \n   \n \n \n \n \n File and Path \n Purpose \n \n \n \n \n scikit-learn/tools/add-venv.* \n The script executed in the previous step (cmd for Windows, sh for Linux/Mac) to create all Python virtual environments required for this tutorial. \n \n \n .venv/scikit-learn-webjob/ \n A virtual environment specifically used for training models. \n \n \n \n scikit-learn/webjob/requirements.txt \n \n The list of packages (with exact versions) required for the scikit-learn-webjob virtual environment. \n \n \n .venv/scikit-learn/ \n A virtual environment specifically used for the Flask application, enabling API endpoint access for querying predictions. \n \n \n scikit-learn/requirements.txt \n The list of packages (with exact versions) required for the scikit-learn virtual environment. \n \n \n scikit-learn/ \n The main folder for this tutorial. \n \n \n scikit-learn/tools/create-folder.* \n A script to create all directories required for this tutorial in the File Share, including train, model, and test. \n \n \n scikit-learn/tools/download-sample-training-set.* \n A script to download a sample training set from the UCI Machine Learning Repository, containing heart disease data, into the train directory of the File Share. \n \n \n scikit-learn/webjob/train_heart_disease_model.py \n A script for training the model. It loads the training set, applies a machine learning algorithm (Logistic Regression), and saves the trained model in the model directory of the File Share. \n \n \n scikit-learn/webjob/train_heart_disease_model.sh \n A shell script for Azure App Service web jobs. It activates the scikit-learn-webjob virtual environment and starts the train_heart_disease_model.py script. \n \n \n scikit-learn/webjob/train_heart_disease_model.zip \n A ZIP file containing the shell script for Azure web jobs. It must be recreated manually whenever train_heart_disease_model.sh is modified. Ensure it does not include any directory structure. \n \n \n scikit-learn/api/app.py \n Code for the Flask application, including routes, port configuration, input parsing, model loading, predictions, and output generation. \n \n \n scikit-learn/.deployment \n A configuration file for deploying the project to Azure using VSCode. It disables the default Oryx build process in favor of custom scripts. \n \n \n scikit-learn/start.sh \n A script executed after deployment (as specified in the Portal's startup command). It sets up the virtual environment and starts the Flask application to handle web requests. \n \n \n \n \n Training Models and Training Data \n Return to VSCode and execute the following commands (their purpose has been described earlier). \n .\\.venv\\scikit-learn-webjob\\Scripts\\Activate.ps1\n.\\scikit-learn\\tools\\create-folder.cmd\n.\\scikit-learn\\tools\\download-sample-training-set.cmd\npython .\\scikit-learn\\webjob\\train_heart_disease_model.py \n If you are using a Linux or Mac platform, use the following alternative commands instead: \n source .venv/scikit-learn-webjob/bin/activate\nbash ./scikit-learn/tools/create-folder.sh\nbash ./scikit-learn/tools/download-sample-training-set.sh\npython ./scikit-learn/webjob/train_heart_disease_model.py \n After execution, the File Share will now include the following directories and files. \n \n Let’s take a brief detour to examine the structure of the training data downloaded from the public dataset website. \n \n The right side of the figure describes the meaning of each column in the dataset, while the left side shows the actual training data (after preprocessing). \n This is a predictive model that uses an individual’s physiological characteristics to determine the likelihood of having heart disease. Columns 1-13 represent various physiological features and background information of the patients, while Column 14 (originally Column 58) is the label indicating whether the individual has heart disease. \n The supervised learning process involves using a large dataset containing both features and labels. Machine learning algorithms (such as neural networks, SVMs, or in this case, logistic regression) identify the key features and their ranges that differentiate between labels. The trained model is then saved and can be used in services to predict outcomes in real time by simply providing the necessary features. \n Predicting with the Model \n Return to VSCode and execute the following commands. First, deactivate the virtual environment used for training the model, then activate the virtual environment for the Flask application, and finally, start the Flask app. \n Commands for Windows: \n deactivate\n.\\.venv\\scikit-learn\\Scripts\\Activate.ps1\npython .\\scikit-learn\\api\\app.py \n Commands for Linux or Mac: \n deactivate\nsource .venv/scikit-learn/bin/activate\npython ./scikit-learn/api/app.py \n When you see a screen similar to the following, it means the server has started successfully. Press Ctrl+C to stop the server if needed. \n \n Before conducting the actual test, let’s construct some sample human feature data: \n [63, 1, 3, 145, 233, 1, 0, 150, 0, 2.3, 0, 0, 1]\n[63, 1, 3, 305, 233, 1, 0, 150, 0, 2.3, 0, 0, 1] \n Referring to the feature description table from earlier, we can see that the only modified field is Column 4 (\"Resting Blood Pressure\"), with the second sample having an abnormally high value. (Note: Normal resting blood pressure ranges are typically 90–139 mmHg.) \n Next, open a PowerShell terminal and use the following curl commands to send requests to the app: \n curl -X GET http://127.0.0.1:8000/api/detect -H \"Content-Type: application/json\" -d '{\"info\": [63, 1, 3, 145, 233, 1, 0, 150, 0, 2.3, 0, 0, 1]}'\ncurl -X GET http://127.0.0.1:8000/api/detect -H \"Content-Type: application/json\" -d '{\"info\": [63, 1, 3, 305, 233, 1, 0, 150, 0, 2.3, 0, 0, 1]}' \n You should see the prediction results, confirming that the trained model is working as expected. \n 5. Publishing the Project to Azure \n Deployment \n In the VSCode interface, right-click on the target App Service where you plan to deploy your project. Manually select the local project folder named scikit-learn as the deployment source, as shown in the image below. \n \n Configuration \n After deployment, the App Service will not be functional yet and will still display the default welcome page. This is because the App Service has not been configured to build the virtual environment and start the Flask application. \n To complete the setup, go to the Azure Portal and navigate to the App Service. The following steps are critical, and their execution order must be correct. To avoid delays, it’s recommended to open two browser tabs beforehand, complete the settings in each, and apply them in sequence. \n Refer to the following two images for guidance. You need to do the following: \n \n Set the Startup Command: Specify the path to the script you deployed \n \n bash /home/site/wwwroot/start.sh \n \n Set Two App Settings:\n \n \n \n \n \n \n WEBSITES_CONTAINER_START_TIME_LIMIT=600 \n The value is in seconds, ensuring the Startup Command can continue execution beyond the default timeout of 230 seconds. This tutorial’s Startup Command typically takes around 300 seconds, so setting it to 600 seconds provides a safety margin and accommodates future project expansion (e.g., adding more packages). \n \n \n WEBSITES_ENABLE_APP_SERVICE_STORAGE=1 \n This setting is required to enable the App Service storage feature, which is necessary for using web jobs (e.g., for model training). \n \n \n \n \n \n \n \n \n Step-by-Step Process: \n \n \n Before clicking Continue, switch to the next browser tab and set up all the app settings. \n \n \n In the second tab, apply all app settings, then switch back to the first tab. \n \n \n Click Continue in the first tab and wait for several seconds for the operation to complete. \n \n \n Once completed, switch to the second tab and click Continue within 5 seconds. \n \n \n Ensure to click Continue promptly within 5 seconds after the previous step to finish all settings. \n \n \n \n After completing the configuration, wait for about 10 minutes for the settings to take effect. Then, navigate to the WebJobs section in the Azure Portal and upload the ZIP file mentioned in the earlier sections. Set its trigger type to Manual. \n \n At this point, the entire deployment process is complete. For future code updates, you only need to redeploy from VSCode; there is no need to reconfigure settings in the Azure Portal. \n 6. Running on Azure Web App \n Training the Model \n Go to the Azure Portal, locate your App Service, and navigate to the WebJobs section. Click on Start to initiate the job and wait for the results. During this process, you may need to manually refresh the page to check the status of the job execution. Refer to the image below for guidance. \n \n Once you see the model report in the Logs, it indicates that the model training is complete, and the Flask app is ready for predictions. \n You can also find the newly trained model in the File Share mounted in your local environment. \n \n Using the Model for Prediction \n Just like in local testing, open a PowerShell terminal and use the following curl commands to send requests to the app: \n # Note: Replace both instances of scikit-learn-portal-app with the name of your web app.\ncurl -X GET https://scikit-learn-portal-app.azurewebsites.net/api/detect -H \"Content-Type: application/json\" -d '{\"info\": [63, 1, 3, 145, 233, 1, 0, 150, 0, 2.3, 0, 0, 1]}'\ncurl -X GET https://scikit-learn-portal-app.azurewebsites.net/api/detect -H \"Content-Type: application/json\" -d '{\"info\": [63, 1, 3, 305, 233, 1, 0, 150, 0, 2.3, 0, 0, 1]}' \n As with the local environment, you should see the expected results. \n 7. Troubleshooting \n Missing Environment Variables After Deployment \n \n Symptom: Even after setting values in App Settings (e.g., WEBSITES_CONTAINER_START_TIME_LIMIT), they do not take effect. \n Cause: App Settings (e.g., WEBSITES_CONTAINER_START_TIME_LIMIT, WEBSITES_ENABLE_APP_SERVICE_STORAGE) are reset after updating the startup command. \n Resolution: Use Azure CLI or the Azure Portal to reapply the App Settings after deployment. Alternatively, set the startup command first, and then apply app settings. \n \n Virtual Environment Resource Lock Issues \n \n Symptom: The app fails to redeploy, even though no configuration or code changes were made. \n Cause: The virtual environment folder cannot be deleted due to active resource locks from the previous process. Files or processes from the previous virtual environment session remain locked. \n Resolution: Deactivate processes before deletion and use unique epoch-based folder names to avoid conflicts. Refer to scikit-learn/start.sh in this tutorial for implementation. \n \n Package Version Dependency Issues \n \n Symptom: Conflicts occur between package versions specified in requirements.txt and the versions required by the Python environment. This results in errors during installation or runtime. \n Cause: Azure deployment environments enforce specific versions of Python and pre-installed packages, leading to mismatches when older or newer versions are explicitly defined. Additionally, the read-only file system in Azure App Service prevents modifying global packages like typing-extensions. \n Resolution: Pin compatible dependency versions. For example, follow the instructions for installing scikit-learn from the scikit-learn 1.5.2 documentation. Refer to scikit-learn/requirements.txt in this tutorial. \n \n Default Binding \n \n Symptom: Despite setting the WEBSITES_PORT parameter in App Settings to match the port Flask listens on (e.g., Flask's default 5000), the deployment still fails. \n Cause: The Flask framework's default settings are not overridden to bind to 0.0.0.0 or the required port. \n Resolution: Explicitly bind Flask to 0.0.0.0:8000 in app.py . To avoid additional issues, it’s recommended to use the Azure Python Linux Web App's default port (8000), as this minimizes the need for extra configuration. \n \n Missing System Commands in Restricted Environments \n \n Symptom: In the WebJobs log, an error is logged stating that the ls command is missing. \n Cause: This typically occurs in minimal environments, such as Azure App Services, containers, or highly restricted shells. \n Resolution: Use predefined paths or variables in the script instead of relying on system commands. Refer to scikit-learn/webjob/train_heart_disease_model.sh in this tutorial for an example of handling such cases. \n \n 8. Conclusion \n Azure App Service, while being a PaaS product with less flexibility compared to a VM, still offers several powerful features that allow us to fully leverage the benefits of AI frameworks. For example, the resource-intensive model training phase can be offloaded to a high-performance local machine. This approach enables the App Service to focus solely on loading models and serving predictions. Additionally, if the training dataset is frequently updated, we can configure WebJobs with scheduled triggers to retrain the model periodically, ensuring the prediction service always uses the latest version. These capabilities make Azure App Service well-suited for most business scenarios. \n 9. References \n \n Scikit-learn Documentation \n UCI Machine Learning Repository \n Azure App Service Documentation \n \n   ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"18169","kudosSumWeight":1,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LU5iOVhQaw?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWtrQWFLaQ?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWFWRGdwUw?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWMyTlQxNg?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWU5d3R2QQ?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUtEdzNYMA?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDc","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LVplNHFlUQ?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDg","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LXRPWmxWVQ?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDk","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTZzWmZYRg?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEw","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUlSSFJWVw?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEx","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LW9wNlBlMQ?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEy","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUF0aXR4MA?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDEz","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LXhlNU9KZA?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE0","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUFyV25UTA?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE1","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTQxZXVIUg?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE2","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUEyRUo1dw?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE3","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTZ0bVJMNg?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE4","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTJSTXo0bA?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE5","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LUVHRXFORQ?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIw","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LTBjNEt5Qw?revision=12\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDIx","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00Mjk0OTk5LWV4dVl6Tg?revision=12\"}"}}],"totalCount":21,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:4163463":{"__typename":"Conversation","id":"conversation:4163463","topic":{"__typename":"BlogTopicMessage","uid":4163463},"lastPostingActivityTime":"2024-06-09T20:01:24.720-07:00","solved":false},"User:user:1149561":{"__typename":"User","uid":1149561,"login":"Raven_Zhang","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/dS0xMTQ5NTYxLTMzOTg5OWlBREM0RTA3OENDQTBDNUJF"},"id":"user:1149561"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5NmlFNkE1QTc3QzI0MDVBMEYz?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5NmlFNkE1QTc3QzI0MDVBMEYz?revision=1","title":"Raven_Zhang_8-1717932282759.png","associationType":"BODY","width":1256,"height":769,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5N2k1MzQwNjBGQzRDNTVGN0I4?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5N2k1MzQwNjBGQzRDNTVGN0I4?revision=1","title":"Raven_Zhang_9-1717932299585.png","associationType":"BODY","width":466,"height":55,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5OGlERkY4MjZFRTdGQ0M1QjY3?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5OGlERkY4MjZFRTdGQ0M1QjY3?revision=1","title":"Raven_Zhang_10-1717932312649.png","associationType":"BODY","width":1709,"height":470,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5OWk5MTU5RjFBNTczREYyMDY2?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5OWk5MTU5RjFBNTczREYyMDY2?revision=1","title":"Raven_Zhang_11-1717932320969.png","associationType":"BODY","width":592,"height":1026,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwMGk0QzUyNTE2RTMwMDE1REM4?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwMGk0QzUyNTE2RTMwMDE1REM4?revision=1","title":"Raven_Zhang_12-1717932344685.png","associationType":"BODY","width":2145,"height":542,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwMWk0MzAwQTIyNzFBQjdCNUE4?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwMWk0MzAwQTIyNzFBQjdCNUE4?revision=1","title":"Raven_Zhang_13-1717932351133.png","associationType":"BODY","width":1689,"height":1308,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwMmk5MzYxOUJEQ0QyNjkxNEM0?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwMmk5MzYxOUJEQ0QyNjkxNEM0?revision=1","title":"Raven_Zhang_14-1717932370946.png","associationType":"BODY","width":2110,"height":812,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwM2lBRTAzNTVBODlCNDY0QUZB?revision=1\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwM2lBRTAzNTVBODlCNDY0QUZB?revision=1","title":"Raven_Zhang_15-1717932384982.png","associationType":"BODY","width":1534,"height":708,"altText":null},"BlogTopicMessage:message:4163463":{"__typename":"BlogTopicMessage","subject":"Steps to Manually Add PowerShell Modules in Function App","conversation":{"__ref":"Conversation:conversation:4163463"},"id":"message:4163463","revisionNum":1,"uid":4163463,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:1149561"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" When using Azure Function Apps on a Consumption plan, you may encounter issues with dependency management due to the 500 MB temp storage limit, causing module installation failures. To avoid upgrading to a more expensive premium plan, you can manually add PowerShell modules using the provided steps. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":4594},"postTime":"2024-06-09T20:01:24.720-07:00","lastPublishTime":"2024-06-09T20:01:24.720-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Function App lets you leverage PowerShell gallery for managing dependencies. Your PowerShell modules defined in requirements.psd1 file will be downloaded automatically if you enable dependency management. However, if your Function App runs on Consumption plan and the size of dependent modules is too large, chances are the download would fail. During the installation, the modules would be unziped and saved in the \"D:\\local\\Temp\", which is the temp storage on the plan worker. Due to the 500 MB limit of temp storage on consumption plan, the installation would fail with not enough space error: \n   \n System Log: { Log-Level: Warning; Log-Message: Save-Module('Microsoft.Graph', '2.18.0'): Package 'Microsoft.Graph.Files' failed to be installed because: There is not enough space on the disk. : 'C:\\local\\Temp\\282636592\\Microsoft.Graph.Files.2.18.0\\bin\\Microsoft.Graph.Files.private.dll' } \n \n The easiest workaround is to scale up the function app plan to premium plan, as premium plan has much larger temp file size. However, this is not the most cost-saving option. You can install the module seperately to the app without depending on the dependency management feature either from local deployment or manual installation from the portal. Here I provide the steps with the second option to add the PowerShell modules directly using \"Advanced Tools\". \n   \n \n \n Find and download modules from PowerShell Gallery to your local system. You should choose \"manual download\" and download the .nupkg files of the modules.  \n \n \n Unzip the .nupkg files and rename the folder to the module official name without the version number.  \n \n \n Open \"App Service Editor\" and create a new folder with name \"Modules\" under \"wwwroot\" folder.  \n \n \n Go to SCM site of the Function App and navigate to \"C:\\home\\site\\wwwroot\\Modules\" path on the file system.  \n \n \n Drag and drop the module package that you have downloaded before to the \"Modules\" folder on the SCM site. \n \n \n Go to \"App Files\", modify the \"requirements.psd1\" as the following, with the corresponding version number of the module:  \n \n \n In \"host.json file\", verify the managedDependency setting has a value of \"Enabled\" and is set to \"False\".  \n \n \n Restart the app, which is very important. \n \n \n Now, you have successfully added the PowerShell modules to the Function App running on consumption plan, minus the \"not enough space\" error. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"2494","kudosSumWeight":4,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5NmlFNkE1QTc3QzI0MDVBMEYz?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5N2k1MzQwNjBGQzRDNTVGN0I4?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5OGlERkY4MjZFRTdGQ0M1QjY3?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDA5OWk5MTU5RjFBNTczREYyMDY2?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwMGk0QzUyNTE2RTMwMDE1REM4?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwMWk0MzAwQTIyNzFBQjdCNUE4?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDc","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwMmk5MzYxOUJEQ0QyNjkxNEM0?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDg","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTYzNDYzLTU5MDEwM2lBRTAzNTVBODlCNDY0QUZB?revision=1\"}"}}],"totalCount":8,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:4055618":{"__typename":"Conversation","id":"conversation:4055618","topic":{"__typename":"BlogTopicMessage","uid":4055618},"lastPostingActivityTime":"2024-03-27T23:05:38.182-07:00","solved":false},"User:user:1730426":{"__typename":"User","uid":1730426,"login":"James_Yu320","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/m_assets/avatars/default/avatar-12.svg?time=0"},"id":"user:1730426"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExMmkxNUJEQzZEQzBDODFDMTFC?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExMmkxNUJEQzZEQzBDODFDMTFC?revision=2","title":"James_Yu320_0-1707811466702.png","associationType":"TEASER","width":1193,"height":502,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExM2kzMTJCNUY5RkY5RDZFMTcw?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExM2kzMTJCNUY5RkY5RDZFMTcw?revision=2","title":"James_Yu320_1-1707811815813.png","associationType":"BODY","width":644,"height":542,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTEyMmkxQkM3QTE1MDhDMUFEMzZC?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTEyMmkxQkM3QTE1MDhDMUFEMzZC?revision=2","title":"James_Yu320_10-1707812283883.png","associationType":"BODY","width":776,"height":333,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExNWkwOUUzRkEyRDdDNjhFRDJD?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExNWkwOUUzRkEyRDdDNjhFRDJD?revision=2","title":"James_Yu320_3-1707812005205.png","associationType":"BODY","width":628,"height":782,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExNmk3OUNDMUE0QjU5OTQwMUM4?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExNmk3OUNDMUE0QjU5OTQwMUM4?revision=2","title":"James_Yu320_4-1707812009853.png","associationType":"BODY","width":608,"height":400,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExN2k0QzA0OENFNTQ0NURGRTA2?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExN2k0QzA0OENFNTQ0NURGRTA2?revision=2","title":"James_Yu320_5-1707812037129.png","associationType":"BODY","width":800,"height":96,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExOGkwRkZENjEwNUE5RjI2MjRD?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExOGkwRkZENjEwNUE5RjI2MjRD?revision=2","title":"James_Yu320_6-1707812055961.png","associationType":"BODY","width":628,"height":380,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTEyMGlGMTc1QTMxQkEzNUU0MTFE?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTEyMGlGMTc1QTMxQkEzNUU0MTFE?revision=2","title":"James_Yu320_8-1707812134276.png","associationType":"BODY","width":1219,"height":327,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTEyMWlFNzNDMjM1NjZEQUYyNzE1?revision=2\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTEyMWlFNzNDMjM1NjZEQUYyNzE1?revision=2","title":"James_Yu320_9-1707812139211.png","associationType":"BODY","width":1300,"height":327,"altText":null},"BlogTopicMessage:message:4055618":{"__typename":"BlogTopicMessage","subject":"Enable Automatic Secret rotation by triggering Azure Function from Event Grid over virtual network","conversation":{"__ref":"Conversation:conversation:4055618"},"id":"message:4055618","revisionNum":2,"uid":4055618,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:1730426"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" \n This blog will demonstrate how to enable Automatic Secret rotation by triggering an Azure Function from Event Grid over a virtual network. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":10012},"postTime":"2024-02-19T01:30:32.187-08:00","lastPublishTime":"2024-02-19T01:30:32.187-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Background: In most cases, the best authentication method for Azure services is by using a managed identity. However, there are scenarios where this may not be an option, and access keys or passwords are used. In such cases, it is important to rotate access keys and passwords regularly. \n   \n Automatic Secret rotation solution: Based on the document (https://learn.microsoft.com/en-us/azure/key-vault/secrets/tutorial-rotation-dual?tabs=azure-cli), it proposes a solution to generate new access keys on storage account and update it in the key vault based on the secret expiry time. It uses Azure Event Grid to send the secret expiry event to an Azure Function App (aka the Azure Function App triggered by Azure Event Grid notifications) – which in turn generates the new access key and updates the secret in the Key vault to automate the periodic rotation of secret. \n \n   \n But it has a limitation as follows: The EventGrid System Topic cannot deliver events to the target which has “Public access disabled and only private endpoint enabled” (the block enclosed in red in the above screenshot) \n   \n To overcome this limitation a few tweaks to the architecture need to be made, which are presented in the following sections of this document. We introduce an Azure Event Hubs in the architecture with public access disabled but “allow trusted microsoft service to bypass” setting enabled. \n   \n Secret Rotation when private endpoints are enabled: \n \n   \n 1. Configure event subscription on the Azure Key Vault. Thirty days before the expiration date of a secret, Key Vault publishes the near expiry event to Event Grid. \n \n   \n 2. Event Grid checks the event subscriptions and delivers the event to the Event Hub endpoint. The managed identity of the Event Grid should have “Azure Event Hub data sender” role assigned in the Event Hub. “Allow trusted Microsoft services to bypass this firewall” setting must be enabled on the Event hub namespace and public access disabled. \n   \n Event Hubs -> Networking blade: \n \n   \n 3. The event hub triggers the function app. \n 4. The function app (created with event hub trigger) identifies the key and calls the storage account to regenerate it. \n 5. The function app adds the newly regenerated key to Azure Key Vault as the new version of the secret. \n   \n The function app managed identity should be assigned the following roles: 1. Key Vault secret officer role on the key vault (when using RBAC based access model) 2. Storage Account Key Operator Service Role assigned on the storage account to generate access keys. \n \n \n   \n \n   \n The following link has the sample Function app code (PowerShell) which performs the secret rotation in the method \"RoatateSecret\" including RegenerateKey on storage account and AddSecretToKeyVault. (https://github.com/Azure-Samples/keyvault-rotation-storageaccountkey-powershell/blob/main/AKVStorageRotation/run.ps1) \n   \n But it needs a few tweaks as our function app is being triggered by Event hub and not event grid topic directly. The last few lines must be modified in the following way: $eventHubMessages | ConvertTo-Json | Write-Host $eventHubMessages | ForEach-Object { $secretName = $_.subject $keyVaultName = $_.data.VaultName Write-Host \"Key Vault Name: $keyVaultName\" Write-Host \"Secret Name: $secretName\" Write-Host \"Rotation started.\" RotateSecret $keyVAultName $secretName Write-Host \"Secret Rotated Successfully\" } \n   \n Reference: 1.Automate the rotation of a secret for resources that have two sets of authentication credentials \n https://learn.microsoft.com/en-us/azure/key-vault/secrets/tutorial-rotation-dual?tabs=azure-cli \n   \n 2.How to trigger Azure Function from Event Grid over virtual network https://techcommunity.microsoft.com/t5/blogs/blogworkflowpage/blog-id/AppsonAzureBlog/article-id/1715 \n   \n 3.Azure services that support system topics in Azure Event Grid \n https://learn.microsoft.com/en-us/azure/event-grid/system-topics \n   \n 4.Keyvault-rotation-storageaccountkey-powershell \n https://github.com/Azure-Samples/keyvault-rotation-storageaccountkey-powershell/blob/main/AKVStorageRotation/run.ps1 ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"4257","kudosSumWeight":4,"repliesCount":2,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExMmkxNUJEQzZEQzBDODFDMTFC?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExM2kzMTJCNUY5RkY5RDZFMTcw?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTEyMmkxQkM3QTE1MDhDMUFEMzZC?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExNWkwOUUzRkEyRDdDNjhFRDJD?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExNmk3OUNDMUE0QjU5OTQwMUM4?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExN2k0QzA0OENFNTQ0NURGRTA2?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDc","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTExOGkwRkZENjEwNUE5RjI2MjRD?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDg","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTEyMGlGMTc1QTMxQkEzNUU0MTFE?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDk","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MDU1NjE4LTU1MTEyMWlFNzNDMjM1NjZEQUYyNzE1?revision=2\"}"}}],"totalCount":9,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3249054":{"__typename":"Conversation","id":"conversation:3249054","topic":{"__typename":"BlogTopicMessage","uid":3249054},"lastPostingActivityTime":"2024-03-26T00:14:15.751-07:00","solved":false},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1MzQzMGkzMzc3QzBEMUMxMUI2RDVC?revision=18\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1MzQzMGkzMzc3QzBEMUMxMUI2RDVC?revision=18","title":"Raven_Zhang_1-1646655291346.png","associationType":"BODY","width":834,"height":355,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1NTMwMmkyMDFFRjdDRTI4QzE5NTM4?revision=18\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1NTMwMmkyMDFFRjdDRTI4QzE5NTM4?revision=18","title":"Raven_Zhang_0-1647060530200.png","associationType":"BODY","width":999,"height":434,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1MzQzMmk1NDhGQTM4QzQ0OTVCODNE?revision=18\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1MzQzMmk1NDhGQTM4QzQ0OTVCODNE?revision=18","title":"Raven_Zhang_2-1646655291347.png","associationType":"BODY","width":453,"height":274,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1MzQzMWlFODZGQ0YyNTBGQTM1NkQy?revision=18\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1MzQzMWlFODZGQ0YyNTBGQTM1NkQy?revision=18","title":"Raven_Zhang_3-1646655291348.png","associationType":"BODY","width":1319,"height":573,"altText":null},"BlogTopicMessage:message:3249054":{"__typename":"BlogTopicMessage","subject":"How to deploy your Web App from Azure Pipeline with restricted access.","conversation":{"__ref":"Conversation:conversation:3249054"},"id":"message:3249054","revisionNum":18,"uid":3249054,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:1149561"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" More and more users now choose to integrate App Service with Azure DevOps to streamline build and deployment process of their applications. The SCM site is the engine behind App Service for deployment, meaning that the release pipeline of Azure DevOps deploys code to the SCM site of an app. In most scenario, SCM site can be reached through public internet. Therefore, ensuring secure access to the site becomes more important. We can enable access restriction on SCM site or set up other firewall solutions to control incoming traffic to the site. Here we will introduce you on how to identify and whitelist deployment traffic from Azure pipeline to SCM site with access restriction. This article also applies when setting up the same rules in other firewall solutions. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":19099},"postTime":"2022-03-17T21:30:16.386-07:00","lastPublishTime":"2024-03-26T00:14:15.751-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" \n More and more users now choose to integrate App Service with Azure DevOps to streamline build and deployment process of their applications. The SCM site is the engine behind App Service for deployment, meaning that the release pipeline of Azure DevOps deploys code to the SCM site of an app. In most scenario, SCM site can be reached through public internet. Therefore, ensuring secure access to the site becomes more important. We can enable access restriction on SCM site or set up other firewall solutions to control incoming traffic to the site. \n \n Here we will introduce you on how to identify and whitelist deployment traffic from Azure pipeline to SCM site with access restriction. This article also applies when setting up the same rules in other firewall solutions. \n   \n   \n Identify IP ranges coming from the deployment traffic \n   \n Before we get into the topic, let us take a look at on how Azure Pipeline deploys your code. Azure Pipelines use agents to deploy your application. An agent is a VM or a container with installed agent software that runs the pipeline jobs. There are three types of agents used by Azure pipeline to build and deploy your code: \n \n Microsoft-hosted agent \n Self-hosted agents \n VMSS agents \n \n You may check what type of agents you are using for Azure pipelines in Azure DevOps >> Project settings >> Agent pools: \n \n   \n If the pipelines are using self-hosted agents or VMSS agents, then you know how to find out the outbound IPs of the agents. \n   \n If the pipelines use Microsoft-hosted agents (in Azure Pipelines agent pool) to deploy your code, which is the default scenario, it is worth noting that the IP ranges used by Microsoft-hosted agents are subject to change as they are a part of Azure global network. Azure publishes a weekly JSON file listing IP ranges for Azure datacenters, broken out by region. You can find out the IP ranges used by the agents in the same region of your DevOps organization by looking through the JSON file with the format of AzureCloud.<region>, such as AzureCloud.westus.  \n   \n As the IPs of Microsoft-hosted agents' are a part of the \"AzureCloud\" service tag, you can also identify the IP ranges of Microsoft-hosted agents by retrieving information from \"AzureCloud\" service tag along with the region information of your Azure DevOps organization with following Powershell cmdlets (for example if your DevOps organization is in \"westus\"): \n   \n   \n $serviceTags = Get-AzNetworkServiceTag -Location westus\n$azureCloud = $serviceTags.Values | Where-Object { $_.Name -eq \"AzureCloud.westus\" }\n$azureCloud.Properties.AddressPrefixes \n   \n   \n Please note that the IPs of Azure Pipeline (Microsoft-hosted agents) are not a part of the \"AzureDevOps\" service tag . The \"AzureDevOps\" service tag only includes inbound IPs of DevOps service, meaning the IPs are the destination addresses of network traffic. \n   \n   \n Set access restriction rules based on the identified IP ranges \n   \n For self-hosted agents or VMSS agents, you may add the allow rules based on the outbound IPs of the agents to the SCM site. \n   \n For Microsoft-hosted agents, we can allow the traffic by whitelisting \"AzureCloud\" service tag to access SCM site on Azure Portal.  \n \n If you are using Microsoft-hosted agents and you don't want to allow all of the IPs in \"AzureCloud\" service tag to access your web app. (\"AzureCloud\" service tag includes all outbound IPs from Azure datacenters.) You can specify the IPs in the access restriction rules or other firewall rules. As the list of IP ranges in your region is quite long, we can automate the process of adding access restriction rules by running the following Powershell cmdlets (for example if your DevOps organization is in \"westus\"):  \n   \n   \n #Get all outbound IP ranges of Azure datacenters in your region.\n$serviceTags = Get-AzNetworkServiceTag -Location westus\n$azureCloud = $serviceTags.Values | Where-Object { $_.Name -eq \"AzureCloud.westus\" }\n$addressPrefixes = $azureCloud.Properties.AddressPrefixes\n\n#Set the access restriction rules to your web app with the retrived IP ranges.\nforeach($address in $addressPrefixes){\n try{\n Add-AzWebAppAccessRestrictionRule -ResourceGroupName \"ResourceGroup\" -WebAppName \"AppName\" -TargetScmSite -Name \"azure pipeline rule\" -Priority 100 -Action Allow -IpAddress $address\n }\n catch{\n write-host $address\" is not added successfully.\"\n }\n} \n   \n   \n As mentioned before, the IP ranges used by Microsoft-hosted agents are subject to change. You don't have to worry about it if you are using \"AzureCloud\" service tag. But please remember to update them regularly if the exact IP ranges are specified in the rules.  \n   \n To summarize, the IPs of Azure pipeline (Microsoft-hosted agents) are not static, either we can include them in a bigger scope with \"AzureCloud\" service tag to save the management overhead or we can update the IP ranges regularly for a more granular protection. \n   \n Update on 3/26/2024 \n Right now, Microsoft-hosted agents are not able to use service tags. We'll need to follow the IP range allow listing method.  \n Reference: https://learn.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml#service-tags \n   \n For more information: \n   \n Azure Pipelines agents \n Microsoft-hosted agents - Networking \n Set up Azure App Service access restrictions \n Virtual network service tags \n   ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"5636","kudosSumWeight":1,"repliesCount":6,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1MzQzMGkzMzc3QzBEMUMxMUI2RDVC?revision=18\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1NTMwMmkyMDFFRjdDRTI4QzE5NTM4?revision=18\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1MzQzMmk1NDhGQTM4QzQ0OTVCODNE?revision=18\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMjQ5MDU0LTM1MzQzMWlFODZGQ0YyNTBGQTM1NkQy?revision=18\"}"}}],"totalCount":4,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3898637":{"__typename":"Conversation","id":"conversation:3898637","topic":{"__typename":"BlogTopicMessage","uid":3898637},"lastPostingActivityTime":"2023-08-17T01:36:12.681-07:00","solved":false},"User:user:1198238":{"__typename":"User","uid":1198238,"login":"Mengyang","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/dS0xMTk4MjM4LTM2MTM2MWk5OTE4NUJERjNDM0E0NzU4"},"id":"user:1198238"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODk4NjM3LTQ5NzY0Nmk3QUI4NEVDNUQzMjk0RDY1?revision=4\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODk4NjM3LTQ5NzY0Nmk3QUI4NEVDNUQzMjk0RDY1?revision=4","title":"Mengyang_0-1691980123124.png","associationType":"BODY","width":2000,"height":1130,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODk4NjM3LTQ5NzY0N2kyOEZCN0JGODdGQUNEM0RB?revision=4\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODk4NjM3LTQ5NzY0N2kyOEZCN0JGODdGQUNEM0RB?revision=4","title":"Mengyang_1-1691980138884.png","associationType":"BODY","width":2000,"height":460,"altText":null},"BlogTopicMessage:message:3898637":{"__typename":"BlogTopicMessage","subject":"Azure PowerShell Functions - connect SFTP and Storage Account","conversation":{"__ref":"Conversation:conversation:3898637"},"id":"message:3898637","revisionNum":4,"uid":3898637,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:1198238"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" This article will explain how to retrieve storage contents and publish to VM via SFTP. \n   ","introduction":"","metrics":{"__typename":"MessageMetrics","views":8670},"postTime":"2023-08-17T00:49:50.848-07:00","lastPublishTime":"2023-08-17T00:49:50.848-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Background \n Recently, I have touched on a case when the customer would like to interact with Azure PowerShell Function to work with Storage Account and SFTP server. There are some advantages why customers would like to apply for this solution: \n \n PowerShell allows IT admins to apply system-level integration with other components more easily. \n Azure Functions provide the convenience of URI/timer-triggered maintenance tasks. \n \n Demand Analysis \n We will first start with the demand analysis. The task will be divided into the following sections: \n \n Pull the required file contents from Azure Storage Account, and store them inside Azure Function App. \n Upload files to another VM via SFTP. \n To work with Azure resources, we also need to apply proper authentication to enhance security. \n \n Sample Code \n If you are looking for a quick sample code to start with, please navigate to the link below: \n https://github.com/SuperChenSSS/GrabSA_SendSFTP \n The credentials and sensitive data in the project have been erased, so that you can directly use them by changing the property name. For more details about the implementation, please check the following part. \n Prepare for authentication \n In order to work with different Azure resources, we need to grant access to the Azure Function level. The solution will use: \n \n Key Vault to retrieve the SFTP login credentials. \n Managed Identity to allow Azure Functions to work with Key Vault and Storage Account. \n Service Principal for local debugging during test phase. \n \n You can expand to learn more details, or skip this part if you have already configured these. \n Key Vault \n Key Vault is the product for retrieving credentials in a safer way. For info on how to store the credentials and retrieve values, see below links: \n Quickstart - Set & retrieve a secret from Key Vault using PowerShell \n Azure Quickstart - Set and retrieve a secret from Key Vault using Azure portal \n   \n   \n # Azure KeyVault\n$kvName = \"kvSFTP0\"\n# SFTP credentials\n$sftpServer = Get-AzKeyVaultSecret -VaultName $kvName -Name \"sftpServer\" -AsPlainText\n$sftpUsername = Get-AzKeyVaultSecret -VaultName $kvName -Name \"sftpUsername\" -AsPlainText\n$sftpPassword = Get-AzKeyVaultSecret -VaultName $kvName -Name \"sftpPassword\" -AsPlainText \n   \n   \n Managed Identity \n Managed Identity allows Azure Function products to authenticate and work with other resources easily. Normally you would need to maintain many credentials in order to get the permission, but managed identity enables much less configuration. \n Please refer to the below links for detailed steps: \n Managed identities - Azure App Service \n Tutorial: Use a managed identity to access Azure Key Vault - Windows - Microsoft Entra \n No code-level implementation is needed for managed identity. \n Service Principal \n In most cases, before publishing to Azure Functions, you need to conduct code tests to make sure it works as expected. Managed Identity won’t work if it’s in local debugging. This time we will need to add Service Principal for such authentication. \n Service Principal is another way to authenticate, and it will use some parameters to grant the permissions. Please follow the below steps: \n \n Create a Service Principal to access storage via Azure Active Directory (AAD). Access storage with Azure Active Directory \n Go to Key Vault → IAM Control → Assign Key Vault Contributor role under the newly created Service Principal, so that we have permissions from both sides. \n Invoke the Service Principal during code implementation. \n \n   \n   \n # ServicePrincipal for Local Testing\n$AppId = $ENV:APPID\n$AppSecret = $ENV:APPSECRET\n$TenantID= $ENV:TENANTID\n$SecureSecret = $AppSecret | ConvertTo-SecureString -AsPlainText -Force\n$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AppId,$SecureSecret\nConnect-AzAccount -ServicePrincipal -Credential $Credential -Tenant $TenantID \nWrite-Host \"Service Principal Connected\" \n   \n   \n Note that I have referenced the local env variables, and this can be configured in local.settings.json file with project folder. All the parameters can be found by searching for your Service Principal Name → Overview and get all credentials. \n Before publishing to the Azure side, please comment on this section to allow function app to work with managed identity instead. \n Once this is ready, we can move forward to connect to storage and publish via SFTP. \n Connect to Storage Account \n This part will mainly deal with downloading blob files from Storage Account into Azure Functions. We will use Azure Storage SDK to achieve this. \n   \n   \n # Azure Storage info\n$kvName = \"\"\n$storageAccountName = \"\"\n$containerName = \"\"\n$blob_name = \"\"\n\n# Interact with query parameters or the body of the request.\n$cName = $Request.Query.cName\n$bName = $Request.Query.bName\n$saName = $Request.Query.saName\nif(-not $cName -or -not $bName -or -not $saName) {\n $body = \"One of the need params (saName, bName, cName) is missing, Will use default storage account, container and blob: \", $containerName, $blob_name, $storageAccountName , \"\\\\nspecify cName and bName in query parameters to override\"\n Write-Host $body\n} else {\n $containerName = $cName\n $blob_name = $bName\n $storageAccountName = $saName\n $body = \"Will download from following storage account, container and blob: \", $storageAccountName, $containerName, $blob_name\n Write-Host $body\n}\n\n# Connect and download from storage\n$ctx = New-AzStorageContext -StorageAccountName $storageAccountName\n$blob = Get-AzStorageBlob -Context $ctx -Container $containerName -Blob $blob_name\n$sourcePath = \"../\" + $blob.Name # Store Location in Azure Function\nGet-AzStorageBlobContent -Context $ctx -Container $containerName -Blob $blob.Name -Destination $sourcePath -Force # Download \n   \n   \n Note that for this task, I simply retrieve one blob file from Storage Account, and the SDK would allow you to achieve much more than this. Reference to Azure Storage SDK: \n New-AzStorageContext (Az.Storage) \n Get-AzStorageBlob (Az.Storage) \n Get-AzStorageBlobContent (Az.Storage) \n Publish file contents with SFTP \n Secure File Transfer Protocol (SFTP) is a safer way to publish the site contents compared with FTP, and is commonly used in enterprise-level publishing events. To connect with SFTP, we can use default port 22, or custom port to enhance the security. \n   \n   \n # Use Posh-SSH module to create and use SFTP session\nImport-Module Posh-SSH\n\n# SFTP credentials\n$sftpServer = Get-AzKeyVaultSecret -VaultName $kvName -Name \"sftpServer\" -AsPlainText\n$sftpUsername = Get-AzKeyVaultSecret -VaultName $kvName -Name \"sftpUsername\" -AsPlainText\n$sftpPassword = Get-AzKeyVaultSecret -VaultName $kvName -Name \"sftpPassword\" -AsPlainText\n$sftpPort = 22\n\n# Establish SFTP session\n$session = New-SFTPSession -ComputerName $sftpServer -Port $sftpPort -Credential (New-Object System.Management.Automation.PSCredential($sftpUsername, (ConvertTo-SecureString $sftpPassword -AsPlainText -Force))) -AcceptKey\n# Judge if connection is successful\nIf (($session.Host -ne $sftpServer) -or !($session.Connected)){\n Write-Host $session.Connected + \" \" + $session.Host\n Write-Host \"SFTP server Connectivity failed..!\"\n exit 1\n }\n\n# Upload each file to the SFTP server\n$destinationPath = \"/\" #SFTP Server Location\n$sourcePath = \"../\" + $blob.Name # Store Location in Azure Function\nSet-SFTPItem -SessionId $session.SessionId -Path $sourcePath -Destination $destinationPath -Force # Upload to SFTP Server\n\n# Close the SFTP session\nRemove-SFTPSession -SessionId $session.SessionId \n   \n   \n Instead of directly invoking sftp from SSH session, we will need to create one in the PowerShell function. Note that we will use Posh-SSH as the supported module to create and use the SFTP session. Below are references to the SDK: \n GitHub - New-SFTPSession \n GitHub - Set-SFTPItem \n GitHub - Remove-SFTPSession \n Result \n \n \n As you can see, we have managed to retrieve the blob files and send them to VM via SFTP. \n Conclusion \n Before publishing the blog, I have done some research and found there are rarely any posts talking about this implementation, while it is a common scenario if the IT admin wants to use Azure Functions to perform some periodic maintenance tasks. \n Hope the explanation could be helpful, and feel free to let me know if any further questions or queries, thank you. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"8494","kudosSumWeight":0,"repliesCount":2,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODk4NjM3LTQ5NzY0Nmk3QUI4NEVDNUQzMjk0RDY1?revision=4\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zODk4NjM3LTQ5NzY0N2kyOEZCN0JGODdGQUNEM0RB?revision=4\"}"}}],"totalCount":2,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"Conversation:conversation:3099282":{"__typename":"Conversation","id":"conversation:3099282","topic":{"__typename":"BlogTopicMessage","uid":3099282},"lastPostingActivityTime":"2023-08-09T00:23:13.862-07:00","solved":false},"User:user:1074444":{"__typename":"User","uid":1074444,"login":"KevinLi","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/m_assets/avatars/default/avatar-10.svg?time=0"},"id":"user:1074444"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDQzNmkzMUU4OENBM0IyRTlBNURB?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDQzNmkzMUU4OENBM0IyRTlBNURB?revision=9","title":"KevinLi_0-1643782165027.png","associationType":"BODY","width":401,"height":229,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE4Nmk5NkMxOTQ4OEM1QjgyNTkw?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE4Nmk5NkMxOTQ4OEM1QjgyNTkw?revision=9","title":"KevinLi_7-1643728774857.png","associationType":"BODY","width":775,"height":369,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE4OGlGMjZFQUExQ0YxMTNCNjU3?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE4OGlGMjZFQUExQ0YxMTNCNjU3?revision=9","title":"KevinLi_8-1643728774860.png","associationType":"BODY","width":712,"height":581,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE4N2k3MTIzQjQxRDcxQzJCQzA4?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE4N2k3MTIzQjQxRDcxQzJCQzA4?revision=9","title":"KevinLi_9-1643728774862.png","associationType":"BODY","width":874,"height":284,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5Mmk2MjQ2RTA1QTExM0Q0NTU1?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5Mmk2MjQ2RTA1QTExM0Q0NTU1?revision=9","title":"KevinLi_10-1643728774865.png","associationType":"BODY","width":566,"height":538,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5M2k3OUY3NjAzRTVCREUxRERD?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5M2k3OUY3NjAzRTVCREUxRERD?revision=9","title":"KevinLi_11-1643728774867.png","associationType":"BODY","width":1590,"height":588,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDM5MmlGNzkyOTU1NjlCRDg0MkMx?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDM5MmlGNzkyOTU1NjlCRDg0MkMx?revision=9","title":"KevinLi_0-1643764349075.png","associationType":"BODY","width":2046,"height":477,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5NGlFOTcyRUYzRTU4RjZFMjgw?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5NGlFOTcyRUYzRTU4RjZFMjgw?revision=9","title":"KevinLi_12-1643728774870.png","associationType":"BODY","width":1086,"height":1226,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5NmlERkUyMDIxMzRCQzNDNDAy?revision=9\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5NmlERkUyMDIxMzRCQzNDNDAy?revision=9","title":"KevinLi_13-1643728774874.png","associationType":"BODY","width":2252,"height":367,"altText":null},"BlogTopicMessage:message:3099282":{"__typename":"BlogTopicMessage","subject":"Manage Azure Resources using PowerShell Function App with Managed Identity","conversation":{"__ref":"Conversation:conversation:3099282"},"id":"message:3099282","revisionNum":9,"uid":3099282,"depth":0,"board":{"__ref":"Blog:board:AppsonAzureBlog"},"author":{"__ref":"User:user:1074444"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":10675},"postTime":"2022-02-01T22:19:21.985-08:00","lastPublishTime":"2022-02-01T22:19:21.985-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Briefly, this post will provide you a step to step guidance with sample code on how to leverage Azure PowerShell Function App to manage Azure resources and use managed identity for authentication to simplify the workflow. \n   \n Azure PowerShell is a set of cmdlets for managing Azure resources directly from the PowerShell command line. Azure PowerShell is designed to make it easy to learn and get started with, but provides powerful features for automation. \n   \n Azure Functions is a cloud service available on-demand that provides all the continually updated infrastructure and resources needed to run your applications. You focus on the pieces of code that matter most to you, and Functions handles the rest. Functions provides serverless compute for Azure. You can use Functions to build web APIs, respond to database changes, process IoT streams, manage message queues, and more. \n   \n When we combine the Azure PowerShell and Azure Function App, it could make a magic. For example, we can make it automatic to restart a Virtual Machine(s) on schedule. Or update a rule in network security group with a HTTP request. \n In this post, we will take restoring Azure Web App from Snapshot regularly as an example to demonstrate the idea. The general workflow is as follow: \n Create PowerShell Function App -> Enable Managed identity -> Grant related resource permissions to the identity(Function App) -> Integrate Az module in functions -> Test and Run \n The topology is as below, we will grant role permission to Function App from source web app and Destination Web App. Then manage them from the function app. \n \n   \n   \n Steps: \n \n Create a Windows PowerShell Function App from portal \n \n \n   \n \n Set up the managed identity in the new Function App by enabling Identity and saving from portal. It will generate an Object(principal) ID for you automatically. \n \n \n   \n \n Now let's go to the source web app and add role assignment from Access control(IAM): \n \n \n   \n \n To make it simple, we use the role \"Contributor\". \n \n \n   \n \n Choose the Managed identity and find the Function App we just created. \n \n \n   \n \n Repeat steps 3~5 for destination web app to grant permission for the function app. Alternatively, you can assign role at resource group(s) or subscription level. \n \n   \n \n After finishing the role assignment. We will go ahead to install Az modules using managed dependencies by simply going to App files and choose requirements.psd1, then uncomment the line \"# 'Az' = '7.*'\". After then, when the first time we trigger the function, it will take some time to download these dependencies automatically. \n \n \n   \n \n Now we can get back to the function app and go ahead to create a Timer trigger function, note that Azure Functions uses the NCronTab library to interpret NCRONTAB expressions. An NCRONTAB expression is similar to a CRON expression except that it includes an additional sixth field at the beginning to use for time precision in seconds: \n \n {second} {minute} {hour} {day} {month} {day-of-week} \n Reference:  https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=csharp#ncrontab-expressions \n   \n \n \n Leverage below sample code in the function. \n \n Sample Code: \n Replace the source and destination web app, resource groups with yours. \n   \n   \n \n# Input bindings are passed in via param block.\n\nparam($Timer)\n\n# Get the current universal time in the default string format.\n\n$currentUTCtime = (Get-Date).ToUniversalTime()\n\n# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.\n\nif ($Timer.IsPastDue) {\n\n Write-Host \"PowerShell timer is running late!\"\n\n}\n\n$srcWebappname = \"SourceWebApp\"\n\n$srcResourceGroupName = \"SourceGroup\"\n\n$dstWebappname = \"DestinationWebApp\"\n\n$dstResourceGroupName = \"DestinationGroup\"\n\n$snapshot = (Get-AzWebAppSnapshot -ResourceGroupName $srcResourceGroupName -Name $srcWebappname)[0]\n\nWrite-Host \"Start restoring Snapshot from $srcWebappname to $dstWebappname\"\n\nRestore-AzWebAppSnapshot -ResourceGroupName $dstResourceGroupName -Name $dstWebappname -InputObject $snapshot -RecoverConfiguration -Force\n\nWrite-Host \"Done\"\n\n# Write an information log with the current time.\n\nWrite-Host \"PowerShell timer trigger function ran! TIME: $currentUTCtime\" \n   \n   \n Test and Run: \n When we manually trigger it, it should be shown like as below: \n \n All done. Thanks for reading! I hope you have fun in it! \n   ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"4593","kudosSumWeight":3,"repliesCount":3,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDQzNmkzMUU4OENBM0IyRTlBNURB?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE4Nmk5NkMxOTQ4OEM1QjgyNTkw?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE4OGlGMjZFQUExQ0YxMTNCNjU3?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE4N2k3MTIzQjQxRDcxQzJCQzA4?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5Mmk2MjQ2RTA1QTExM0Q0NTU1?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5M2k3OUY3NjAzRTVCREUxRERD?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDc","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDM5MmlGNzkyOTU1NjlCRDg0MkMx?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDg","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5NGlFOTcyRUYzRTU4RjZFMjgw?revision=9\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMXwyLjF8b3wyNXxfTlZffDk","node":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMDk5MjgyLTM0NDE5NmlERkUyMDIxMzRCQzNDNDAy?revision=9\"}"}}],"totalCount":9,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""}},"CachedAsset:text:en_US-components/community/Navbar-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/community/Navbar-1744658876111","value":{"community":"Community Home","inbox":"Inbox","manageContent":"Manage Content","tos":"Terms of Service","forgotPassword":"Forgot Password","themeEditor":"Theme Editor","edit":"Edit Navigation Bar","skipContent":"Skip to content","gxcuf89792":"Tech Community","external-1":"Events","s-m-b":"Small and Medium Businesses","windows-server":"Windows Server","education-sector":"Education Sector","driving-adoption":"Driving Adoption","microsoft-learn":"Microsoft Learn","s-q-l-server":"SQL Server","partner-community":"Microsoft Partner Community","microsoft365":"Microsoft 365","external-9":".NET","external-8":"Teams","external-7":"Github","products-services":"Products","external-6":"Power Platform","communities-1":"Topics","external-5":"Microsoft Security","planner":"Planner","external-4":"Microsoft 365","external-3":"Dynamics 365","azure":"Azure","healthcare-and-life-sciences":"Healthcare and Life Sciences","external-2":"Azure","microsoft-mechanics":"Microsoft Mechanics","microsoft-learn-1":"Community","external-10":"Learning Room Directory","microsoft-learn-blog":"Blog","windows":"Windows","i-t-ops-talk":"ITOps Talk","external-link-1":"View All","microsoft-securityand-compliance":"Microsoft Security","public-sector":"Public Sector","community-info-center":"Lounge","external-link-2":"View All","microsoft-teams":"Microsoft Teams","external":"Blogs","microsoft-endpoint-manager":"Microsoft Intune and Configuration Manager","startupsat-microsoft":"Startups at Microsoft","exchange":"Exchange","a-i":"AI and Machine Learning","io-t":"Internet of Things (IoT)","outlook":"Outlook","external-link":"Community Hubs","communities":"Products"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarHamburgerDropdown-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarHamburgerDropdown-1744658876111","value":{"hamburgerLabel":"Side Menu"},"localOverride":false},"CachedAsset:text:en_US-components/community/BrandLogo-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/community/BrandLogo-1744658876111","value":{"logoAlt":"Khoros","themeLogoAlt":"Brand Logo"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarTextLinks-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarTextLinks-1744658876111","value":{"more":"More"},"localOverride":false},"CachedAsset:text:en_US-components/authentication/AuthenticationLink-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/authentication/AuthenticationLink-1744658876111","value":{"title.login":"Sign In","title.registration":"Register","title.forgotPassword":"Forgot Password","title.multiAuthLogin":"Sign In"},"localOverride":false},"CachedAsset:text:en_US-components/nodes/NodeLink-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/nodes/NodeLink-1744658876111","value":{"place":"Place {name}"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagSubscriptionAction-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagSubscriptionAction-1744658876111","value":{"success.follow.title":"Following Tag","success.unfollow.title":"Unfollowed Tag","success.follow.message.followAcrossCommunity":"You will be notified when this tag is used anywhere across the community","success.unfollowtag.message":"You will no longer be notified when this tag is used anywhere in this place","success.unfollowtagAcrossCommunity.message":"You will no longer be notified when this tag is used anywhere across the community","unexpected.error.title":"Error - Action Failed","unexpected.error.message":"An unidentified problem occurred during the action you took. Please try again later.","buttonTitle":"{isSubscribed, select, true {Unfollow} false {Follow} other{}}","unfollow":"Unfollow"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageListTabs-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListTabs-1744658876111","value":{"mostKudoed":"{value, select, IDEA {Most Votes} other {Most Likes}}","mostReplies":"Most Replies","mostViewed":"Most Viewed","newest":"{value, select, IDEA {Newest Ideas} OCCASION {Newest Events} other {Newest Topics}}","newestOccasions":"Newest Events","mostRecent":"Most Recent","noReplies":"No Replies Yet","noSolutions":"No Solutions Yet","solutions":"Solutions","mostRecentUserContent":"Most Recent","trending":"Trending","draft":"Drafts","spam":"Spam","abuse":"Abuse","moderation":"Moderation","tags":"Tags","PAST":"Past","UPCOMING":"Upcoming","sortBymostRecent":"Sort By Most Recent","sortBymostRecentUserContent":"Sort By Most Recent","sortBymostKudoed":"Sort By Most Likes","sortBymostReplies":"Sort By Most Replies","sortBymostViewed":"Sort By Most Viewed","sortBynewest":"Sort By Newest Topics","sortBynewestOccasions":"Sort By Newest Events","otherTabs":" Messages list in the {tab} for {conversationStyle}","guides":"Guides","archives":"Archives"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/QueryHandler-1744658876111","value":{"title":"Query Handler"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarDropdownToggle-1744658876111","value":{"ariaLabelClosed":"Press the down arrow to open the menu"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/OverflowNav-1744658876111","value":{"toggleText":"More"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageView/MessageViewInline-1744658876111","value":{"bylineAuthor":"{bylineAuthor}","bylineBoard":"{bylineBoard}","anonymous":"Anonymous","place":"Place {bylineBoard}","gotoParent":"Go to parent {name}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Pager/PagerLoadMore-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Pager/PagerLoadMore-1744658876111","value":{"loadMore":"Show More"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserLink-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserLink-1744658876111","value":{"authorName":"View Profile: {author}","anonymous":"Anonymous"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageSubject-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageSubject-1744658876111","value":{"noSubject":"(no subject)"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageBody-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBody-1744658876111","value":{"showMessageBody":"Show More","mentionsErrorTitle":"{mentionsType, select, board {Board} user {User} message {Message} other {}} No Longer Available","mentionsErrorMessage":"The {mentionsType} you are trying to view has been removed from the community.","videoProcessing":"Video is being processed. Please try again in a few minutes.","bannerTitle":"Video provider requires cookies to play the video. Accept to continue or {url} it directly on the provider's site.","buttonTitle":"Accept","urlText":"watch"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageTime-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageTime-1744658876111","value":{"postTime":"Published: {time}","lastPublishTime":"Last Update: {time}","conversation.lastPostingActivityTime":"Last posting activity time: {time}","conversation.lastPostTime":"Last post time: {time}","moderationData.rejectTime":"Rejected time: {time}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeIcon-1744658876111","value":{"contentType":"Content Type {style, select, FORUM {Forum} BLOG {Blog} TKB {Knowledge Base} IDEA {Ideas} OCCASION {Events} other {}} icon"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageUnreadCount-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageUnreadCount-1744658876111","value":{"unread":"{count} unread","comments":"{count, plural, one { unread comment} other{ unread comments}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageViewCount-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageViewCount-1744658876111","value":{"textTitle":"{count, plural,one {View} other{Views}}","views":"{count, plural, one{View} other{Views}}"},"localOverride":false},"CachedAsset:text:en_US-components/kudos/KudosCount-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/kudos/KudosCount-1744658876111","value":{"textTitle":"{count, plural,one {{messageType, select, IDEA{Vote} other{Like}}} other{{messageType, select, IDEA{Votes} other{Likes}}}}","likes":"{count, plural, one{like} other{likes}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageRepliesCount-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageRepliesCount-1744658876111","value":{"textTitle":"{count, plural,one {{conversationStyle, select, IDEA{Comment} OCCASION{Comment} other{Reply}}} other{{conversationStyle, select, IDEA{Comments} OCCASION{Comments} other{Replies}}}}","comments":"{count, plural, one{Comment} other{Comments}}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1744658876111":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserAvatar-1744658876111","value":{"altText":"{login}'s avatar","altTextGeneric":"User's avatar"},"localOverride":false}}}},"page":"/tags/TagPage/TagPage","query":{"nodeId":"board:AppsonAzureBlog","tagName":"powershell"},"buildId":"HEhyUrv5OXNBIbfCLaOrw","runtimeConfig":{"buildInformationVisible":false,"logLevelApp":"info","logLevelMetrics":"info","openTelemetryClientEnabled":false,"openTelemetryConfigName":"o365","openTelemetryServiceVersion":"25.1.0","openTelemetryUniverse":"prod","openTelemetryCollector":"http://localhost:4318","openTelemetryRouteChangeAllowedTime":"5000","apolloDevToolsEnabled":false,"inboxMuteWipFeatureEnabled":false},"isFallback":false,"isExperimentalCompile":false,"dynamicIds":["./components/community/Navbar/NavbarWidget.tsx","./components/community/Breadcrumb/BreadcrumbWidget.tsx","./components/customComponent/CustomComponent/CustomComponent.tsx","./components/tags/TagsHeaderWidget/TagsHeaderWidget.tsx","./components/messages/MessageListForNodeByRecentActivityWidget/MessageListForNodeByRecentActivityWidget.tsx","./components/tags/TagSubscriptionAction/TagSubscriptionAction.tsx","./components/external/components/ExternalComponent.tsx","../shared/client/components/common/List/ListGroup/ListGroup.tsx","./components/messages/MessageView/MessageView.tsx","./components/messages/MessageView/MessageViewInline/MessageViewInline.tsx","../shared/client/components/common/Pager/PagerLoadMore/PagerLoadMore.tsx"],"appGip":true,"scriptLoader":[{"id":"analytics","src":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/pagescripts/1730819800000/analytics.js?page.id=TagPage","strategy":"afterInteractive"}]}